Merge branch 'main' into next

# Conflicts:
#	package.json
#	src/language-css/printer-postcss.js
#	yarn.lock
This commit is contained in:
fisker Cheung committed 2021-03-29 19:47:56 +08:00
commit 85fc1fa017
245 files changed
+7288 -4164

No files matched your search

+3
View File
@@ -58,6 +58,7 @@ rules:
prefer-spread: error
prettier-internal-rules/jsx-identifier-case: error
prettier-internal-rules/require-json-extensions: error
prettier-internal-rules/no-identifier-n: error
quotes:
- error
- double
@@ -117,9 +118,11 @@ overrides:
prettier-internal-rules/better-parent-property-check-in-needs-parens: error
- files: src/**/*.js
rules:
prettier-internal-rules/consistent-negative-index-access: error
prettier-internal-rules/flat-ast-path-call: error
prettier-internal-rules/no-doc-builder-concat: error
prettier-internal-rules/no-empty-flat-contents-for-if-break: error
prettier-internal-rules/no-unnecessary-ast-path-call: error
prettier-internal-rules/prefer-ast-path-each: error
prettier-internal-rules/prefer-indent-if-break: error
prettier-internal-rules/prefer-is-non-empty-array: error
+2 -2
View File
@@ -15,10 +15,10 @@ BEFORE SUBMITTING AN ISSUE:
2. We get a lot of requests for adding options, but Prettier is
built on the principle of being opinionated about code formatting.
This means we have a very high bar for adding new options.
This means we add options only in the case of strict technical necessity.
Find out more: https://prettier.io/docs/en/option-philosophy.html
Tip! Don't write this stuff manually.
Don't fill the form below manually! Let a program create a report for you:
1. Go to https://prettier.io/playground
2. Paste your code and set options
+2 -1
View File
@@ -13,7 +13,7 @@ BEFORE SUBMITTING AN ISSUE:
you do not need to open a new issue — please add a 👍 reaction to the
existing issue instead.
2. If your issue is with a prettier editor extension or add-on, please open the
2. If your issue is with a Prettier editor extension or add-on, please open the
issue in the repo for that extension or add-on, instead of this repo.
-->
@@ -24,6 +24,7 @@ BEFORE SUBMITTING AN ISSUE:
- Running Prettier via: <!-- CLI, Node.js API, Browser API, etc. -->
- Runtime: <!-- Node.js v14, Chrome v83, etc. -->
- Operating System: <!-- Windows, Linux, macOS, etc. -->
- Prettier plugins (if any): <!-- e.g. @prettier/plugin-php -->
**Steps to reproduce:**
+1
View File
@@ -6,6 +6,7 @@ updates:
interval: weekly
day: sunday
time: "01:00"
open-pull-requests-limit: 20
- package-ecosystem: "npm"
directory: "/website"
+2 -2
View File
@@ -66,7 +66,7 @@ jobs:
run: yarn test --maxWorkers=2
- name: Upload Coverage
uses: codecov/codecov-action@v1.2.1
uses: codecov/codecov-action@v1.3.1
if: matrix.ENABLE_CODE_COVERAGE
with:
fail_ci_if_error: true
@@ -78,7 +78,7 @@ jobs:
PRETTIER_FALLBACK_RESOLVE: true
- name: Upload Coverage (PRETTIER_FALLBACK_RESOLVE)
uses: codecov/codecov-action@v1.2.1
uses: codecov/codecov-action@v1.3.1
if: matrix.ENABLE_CODE_COVERAGE
with:
fail_ci_if_error: true
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
if: ${{ !github.event.issue.pull_request && startsWith(github.event.comment.body, 'Duplicate of ') }}
steps:
- uses: actions-cool/issues-helper@v2.1.2
- uses: actions-cool/issues-helper@v2.2.1
with:
actions: "mark-duplicate"
token: ${{ secrets.GITHUB_TOKEN }}
+35
View File
@@ -0,0 +1,35 @@
#### Simplified `print` callback (#10557 by @fisker)
The third argument of the `print` method of plugin printers (the `print` callback) has been updated. Its first argument can be a string or an array of strings now.
To print the current node, call `print` without arguments:
```diff
function print(path, options, print) {
const parts = [];
path.each((childPath) => {
- parts.push(print(childPath));
+ parts.push(print());
}, "children");
return parts;
}
```
To print a property of the current node, use `"property"` or `["property"]`:
```diff
function print(path, options, print) {
- return path.call(print, "property");
+ return print("property");
}
```
To print a sub-property of the current node, use `["property1", "property2"]`:
```diff
function print(path, options, print) {
// print `node.child.child`
- return path.call(print, "child", "child");
+ return print(["child", "child"]);
}
```
@@ -1,4 +1,4 @@
#### Add CLI option to prevent errors on unmatched pattern (#8233 by @daronmcintosh)
#### Add CLI option to prevent errors on unmatched pattern (#10058 by @daronmcintosh)
The following command will not throw an error when it doesn't find a YAML file.
+15
View File
@@ -0,0 +1,15 @@
#### Fix range formatting issues (#10505 by @thorn0)
Prettier had trouble formatting some ranges in function declarations. `SyntaxError` was thrown. Prettier main formats these cases without errors. Examples of problematic ranges are shown below:
<!-- prettier-ignore -->
```jsx
declare export function graphql<Props, Variables, Component: React$ComponentType<Props>>
// ^^^^^ range 1
(query: GQLDocument, config?: Config<Props, QueryConfigOptions<Variables>>):
(Component: Component) => React$ComponentType<$Diff<React$ElementConfig<Component>, {
data: Object|void,
// ^^^^ range 2
mutate: Function|void
}>>
```
+15
View File
@@ -0,0 +1,15 @@
#### Support for Flow's indexed access type (#10594 by @gkz)
Support for Flow's indexed access type.
<!-- prettier-ignore -->
```js
// Input
const x: Obj['foo'] = 1;
// Prettier stable
// Error: unsupported node type "IndexedAccessType"
// Prettier main
const x: Obj["foo"] = 1;
```
+16
View File
@@ -0,0 +1,16 @@
#### Move Handlebars support out of alpha to release (#10290 by @dcyriller & @thorn0)
This started in 2017. Handlebars support has been in Prettier for a while, but it wasn’t released officially as it wasn’t really ready. Its status was “alpha”, “experimental”, “beta”. Then, if you checked older release notes, you could see that after “beta” somehow it was “alpha” again…
Well, anyway, it finally is happening: Prettier can now officially format Handlebars files! 🎉
It uses [Glimmer], [Ember]’s Handlebars parser, so it should be compliant with the HTML spec thanks to the Ember team.
The [`--html-whitespace-sensitivity`][hws-option] option is supported and defaults to `strict`, which means that Prettier will always respect the presence or absence of whitespace around tags and consider it unsafe to add whitespace where there were none and vice versa as this can affect how the document is rendered in the browser. The `css` value is not yet supported (treated as `strict` for now).
The feature is called “Ember / Handlebars” and not just “Handlebars” because Glimmer doesn’t support some syntax and use cases of Handlebars. This is mostly due to the fact that [Handlebars], being a template engine (a preprocessor), doesn’t care about the underlying syntax of the content it processes whereas Glimmer parses two syntaxes – HTML and Handlebars – at the same time and combines the result into a single tree, which Prettier can print. This means Prettier won’t format Handlebars files that can’t be parsed into such a tree, either because the underlying syntax isn’t HTML or because template directives and tags overlap in a way that can’t be represented in a tree (e.g., `{{#if foo}}<div>{{/if}`). Even with these restrictions, the formatter still seems to be useful enough to non-Ember Handlebars users.
[glimmer]: https://www.npmjs.com/package/@glimmer/syntax
[ember]: https://emberjs.com
[hws-option]: https://prettier.io/docs/en/options.html#html-whitespace-sensitivity
[handlebars]: https://handlebarsjs.com/
+13
View File
@@ -0,0 +1,13 @@
#### Preserve numeric character references (#10550 by @rwjblue and @thorn0)
<!-- prettier-ignore -->
```hbs
{{! Input }}
<span class="stampFont" style="font-family: 'stampfont'">&#xf000;</span>
{{! Prettier stable }}
<span class="stampFont" style="font-family: 'stampfont'"></span>
{{! Prettier main }}
<span class="stampFont" style="font-family: 'stampfont'">&#xf000;</span>
```
+18
View File
@@ -0,0 +1,18 @@
#### Support Module Blocks proposal (#10417 by @sosukesuzuki, @thorn0)
Support formatting for [Module Blocks Stage 2 proposal](https://github.com/tc39/proposal-js-module-blocks).
<!-- prettier-ignore -->
```js
// Input
module { export let foo = "foo"; };
// Prettier main
SyntaxError: Unexpected token, expected ";"
// Prettier stable
module {
export let foo = "foo";
};
```
+19
View File
@@ -0,0 +1,19 @@
#### Fix missing parentheses for `yield` in `pipeline` (#10446 by @fisker)
<!-- prettier-ignore -->
```jsx
// Input
function* f() {
return x |> (yield #);
}
// Prettier stable
function* f() {
return x |> yield #;
}
// Prettier main
function* f() {
return x |> (yield #);
}
```
+33
View File
@@ -0,0 +1,33 @@
#### Avoid last-argument hugging for number-only arrays (#10517 by @thorn0)
Another special case for number-only arrays.
<!-- prettier-ignore -->
```jsx
// Input
instantiate(game, [
transform([-0.7, 0.5, 0]),
render_colored_diffuse(game.MaterialDiffuse, game.Meshes["monkey_flat"], [1, 1, 0.3, 1]),
]);
// Prettier stable
instantiate(game, [
transform([-0.7, 0.5, 0]),
render_colored_diffuse(game.MaterialDiffuse, game.Meshes["monkey_flat"], [
1,
1,
0.3,
1,
]),
]);
// Prettier main
instantiate(game, [
transform([-0.7, 0.5, 0]),
render_colored_diffuse(
game.MaterialDiffuse,
game.Meshes["monkey_flat"],
[1, 1, 0.3, 1]
),
]);
```
+23
View File
@@ -0,0 +1,23 @@
#### Improve detection of AMD `define` (#10528 by @thorn0)
Prettier special-cases AMD `define` calls to avoid unexpected line breaks in them. `define` calls that weren't expression statements and had nothing to do with AMD were formatted this way too. This happens no longer.
<!-- prettier-ignore -->
```jsx
// Input
const someVariable = define(
"some string literal",
anotherVariable,
yetAnotherVariable
);
// Prettier stable
const someVariable = define("some string literal", anotherVariable, yetAnotherVariable);
// Prettier main
const someVariable = define(
"some string literal",
anotherVariable,
yetAnotherVariable
);
```
+1 -1
View File
@@ -1,4 +1,4 @@
#### Refine formatting of curried arrow functions (#9992 by @sosukesuzuki and @thorn0)
#### Refine formatting of curried arrow functions (#9992, #10543 by @sosukesuzuki & @thorn0)
<!-- prettier-ignore -->
```js
+1 -1
View File
@@ -1,4 +1,4 @@
#### Stricter JSON parser (#10346, #10443, #10456 by @fisker)
#### Stricter JSON parser (#10346, #10443, #10456, #10434 by @fisker)
Prettier internally uses a JavaScript expression parser to parse JSON. That's why the `json` and `json5` parsers used to be very forgiving and allowed all kinds of JavaScript expressions. Now they are much stricter, although some simple non-standard syntax is still allowed (e.g., [JSON6](https://github.com/d3x0r/JSON6) is supported, except for multiple minus signs: `----123`).
+16
View File
@@ -0,0 +1,16 @@
#### Fix syntax error on JSON range formatting (#10497 by @fisker)
<!-- prettier-ignore -->
```js
// Input
[{ a: 1.0000}, {"b": 2.0000 }]
// ^^^^^^^^^^^ range
// Prettier stable
SyntaxError: Unexpected token (1:4)
> 1 | "b": 2.0000
| ^
// Prettier main
[{ a: 1.0000}, { "b": 2.0 }]
```
+17 -2
View File
@@ -1,6 +1,6 @@
#### Support TypeScript 4.2 `abstract` Construct Signatures (#10418, #10466 by @sosukesuzuki)
#### Support TypeScript 4.2 (#10418, #10466, #10546, #10589 by @sosukesuzuki)
Support [`abstract` Construct Signatures](https://devblogs.microsoft.com/typescript/announcing-typescript-4-2/#abstract-construct-signatures).
##### [`abstract` Construct Signatures](https://devblogs.microsoft.com/typescript/announcing-typescript-4-2/#abstract-construct-signatures)
<!-- prettier-ignore -->
```ts
@@ -14,3 +14,18 @@ SyntaxError: Unexpected token, expected ";" (1:19)
type T = abstract new () => void;
```
##### [Type imports in import require declaration](https://github.com/microsoft/TypeScript/pull/41573)
<!-- prettier-ignore -->
```ts
// Input
import type A = require("A");
// Prettier main
SyntaxError: Only ECMAScript imports may use 'import type'.
// Prettier stable
import type A = require("A");
```
+24
View File
@@ -0,0 +1,24 @@
#### Fix SyntaxError incorrectly thrown on anchors followed by empty lines (#10516 by @eemeli & @thorn0)
Prettier couldn't parse this valid YAML. Thanks to Eemeli Aro for fixing this bug in the underlying parser.
<!-- prettier-ignore -->
```yaml
# Input
key1: &default
subkey1: value1
key2:
<<: *default
# Prettier stable
SyntaxError: Nested mappings are not allowed in compact mappings (1:7)
# Prettier main
key1: &default
subkey1: value1
key2:
<<: *default
```
+1 -1
View File
@@ -213,7 +213,7 @@ Decrease the level of indentation. (Each `align` is considered one level of inde
### `align`
```ts
declare function align(n: number | string, doc: Doc): Doc;
declare function align(widthOrString: number | string, doc: Doc): Doc;
```
Increase the indentation by a fixed number of spaces or a string. A variant of [`indent`](#indent).
+1
View File
@@ -102,6 +102,7 @@
"duailibe",
"Duperron",
"editorconfig",
"eemeli",
"ekkhus",
"elektronik",
"Eneman",
+2 -2
View File
@@ -9,9 +9,9 @@ If you want to run Prettier programmatically, check this page out.
const prettier = require("prettier");
```
## `prettier.format(source [, options])`
## `prettier.format(source, options)`
`format` is used to format text using Prettier. [Options](options.md) may be provided to override the defaults. Set `options.parser` according to the language you are formatting (see the [list of available parsers](options.md#parser)).
`format` is used to format text using Prettier. `options.parser` must be set according to the language you are formatting (see the [list of available parsers](options.md#parser)). Alternatively, `options.filepath` can be specified for Prettier to infer the parser from the file extension. Other [options](options.md) may be provided to override the defaults.
```js
prettier.format("foo ( );", { semi: false, parser: "babel" });
+45 -32
View File
@@ -3,7 +3,7 @@ id: browser
title: Browser
---
Run Prettier in the browser using its **standalone** version. This version only formats the code and has no support for config files, ignore files, CLI usage, or automatic loading of plugins.
Run Prettier in the browser using its **standalone** version. This version doesn’t depend on Node.js. It only formats the code and has no support for config files, ignore files, CLI usage, or automatic loading of plugins.
The standalone version comes as:
@@ -14,42 +14,18 @@ The [`browser` field](https://github.com/defunctzombie/package-browser-field-spe
### `prettier.format(code, options)`
Unlike the `format` function from the [main API](api.md#prettierformatsource--options), this function does not load plugins automatically, so a `plugins` property is required if you want to load [plugins](#plugins). Additionally, the parsers included in the Prettier package won’t be loaded automatically, so you need to load them as plugins before using them.
Required options:
See [Usage](#usage) below for examples.
- **[`parser`](options.md#parser) (or [`filepath`](options.md#file-path))**: One of these options has to be specified for Prettier to know which parser to use.
## Plugins
- **`plugins`**: Unlike the `format` function from the [Node.js-based API](api.md#prettierformatsource--options), this function doesn’t load plugins automatically. The `plugins` option is required because all the parsers included in the Prettier package come as plugins (for reasons of file size). These plugins are files named
All available plugins are files named `parser-*.js` in <https://unpkg.com/browse/prettier@2.2.1/> and `parser-*.mjs` in <https://unpkg.com/browse/prettier@2.2.1/esm/>.
- `parser-*.js` in <https://unpkg.com/browse/prettier@2.2.1/> and
- `parser-*.mjs` in <https://unpkg.com/browse/prettier@2.2.1/esm/>
If you want format embed code, you need load related plugins too, for example
You need to load the ones that you’re going to use and pass them to `prettier.format` using the `plugins` option.
```html
<script type="module">
import prettier from "https://unpkg.com/prettier@2.2.1/esm/standalone.mjs";
import parserBabel from "https://unpkg.com/prettier@2.2.1/esm/parser-babel.mjs";
prettier.format("const html = /* HTML */ `<DIV> </DIV>`", {
parser: "babel",
plugins: [parserBabel],
});
</script>
```
the HTML code inside JavaScript code won't get formatted, because it requires `html` parser too, correct usage
```html
<script type="module">
import prettier from "https://unpkg.com/prettier@2.2.1/esm/standalone.mjs";
import parserBabel from "https://unpkg.com/prettier@2.2.1/esm/parser-babel.mjs";
import parserHtml from "https://unpkg.com/prettier@2.2.1/esm/parser-html.mjs";
prettier.format("const html = /* HTML */ `<DIV> </DIV>`", {
parser: "babel",
plugins: [parserBabel, parserHtml],
});
</script>
```
See below for examples.
## Usage
@@ -119,3 +95,40 @@ prettier.format("type Query { hello: String }", {
plugins: prettierPlugins,
});
```
## Parser plugins for embedded code
If you want to format [embedded code](options.md#embedded-language-formatting), you need to load related plugins too. For example:
```html
<script type="module">
import prettier from "https://unpkg.com/prettier@2.2.1/esm/standalone.mjs";
import parserBabel from "https://unpkg.com/prettier@2.2.1/esm/parser-babel.mjs";
console.log(
prettier.format("const html=/* HTML */ `<DIV> </DIV>`", {
parser: "babel",
plugins: [parserBabel],
})
);
// Output: const html = /* HTML */ `<DIV> </DIV>`;
</script>
```
The HTML code embedded in JavaScript stays unformatted because the `html` parser hasn’t been loaded. Correct usage:
```html
<script type="module">
import prettier from "https://unpkg.com/prettier@2.2.1/esm/standalone.mjs";
import parserBabel from "https://unpkg.com/prettier@2.2.1/esm/parser-babel.mjs";
import parserHtml from "https://unpkg.com/prettier@2.2.1/esm/parser-html.mjs";
console.log(
prettier.format("const html=/* HTML */ `<DIV> </DIV>`", {
parser: "babel",
plugins: [parserBabel, parserHtml],
})
);
// Output: const html = /* HTML */ `<div></div>`;
</script>
```
-16
View File
@@ -114,22 +114,6 @@ If you don’t have a configuration file, or want to ignore it if it does exist,
Path to a file containing patterns that describe files to ignore. By default, Prettier looks for `./.prettierignore`.
## `--require-pragma`
Require a special comment, called a pragma, to be present in the file’s first docblock comment in order for Prettier to format it.
```js
/**
* @prettier
*/
```
Valid pragmas are `@prettier` and `@format`.
## `--insert-pragma`
Insert a `@format` pragma to the top of formatted files when pragma is absent. Works well when used in tandem with `--require-pragma`.
## `--list-different`
Another useful flag is `--list-different` (or `-l`) which prints the filenames of files that are different from Prettier formatting. If there are differences the script errors out, which is useful in a CI scenario.
+7 -3
View File
@@ -267,9 +267,9 @@ This option is only useful in the CLI and API. It doesn’t make sense to use it
_First available in v1.7.0_
Prettier can restrict itself to only format files that contain a special comment, called a pragma, at the top of the file. This is very useful when gradually transitioning large, unformatted codebases to prettier.
Prettier can restrict itself to only format files that contain a special comment, called a pragma, at the top of the file. This is very useful when gradually transitioning large, unformatted codebases to Prettier.
For example, a file with the following as its first comment will be formatted when `--require-pragma` is supplied:
A file with the following as its first comment will be formatted when `--require-pragma` is supplied:
```js
/**
@@ -293,12 +293,16 @@ or
_First available in v1.8.0_
Prettier can insert a special @format marker at the top of files specifying that the file has been formatted with prettier. This works well when used in tandem with the `--require-pragma` option. If there is already a docblock at the top of the file then this option will add a newline to it with the @format marker.
Prettier can insert a special `@format` marker at the top of files specifying that the file has been formatted with Prettier. This works well when used in tandem with the `--require-pragma` option. If there is already a docblock at the top of the file then this option will add a newline to it with the `@format` marker.
Note that “in tandem” doesn’t mean “at the same time”. When the two options are used simultaneously, `--require-pragma` has priority, so `--insert-pragma` is ignored. The idea is that during an incremental adoption of Prettier in a big codebase, the developers participating in the transition process use `--insert-pragma` whereas `--require-pragma` is used by the rest of the team and automated tooling to process only files already transitioned. The feature has been inspired by Facebook’s [adoption strategy].
| Default | CLI Override | API Override |
| ------- | ----------------- | ---------------------- |
| `false` | `--insert-pragma` | `insertPragma: <bool>` |
[adoption strategy]: https://prettier.io/blog/2017/05/03/1.3.0.html#facebook-adoption-update
## Prose Wrap
_First available in v1.8.2_
+33 -9
View File
@@ -40,7 +40,6 @@ Providing at least one path to `--plugin-search-dir`/`pluginSearchDirs` turns of
- [`@prettier/plugin-php`](https://github.com/prettier/plugin-php)
- [`@prettier/plugin-pug`](https://github.com/prettier/plugin-pug) by [**@Shinigami92**](https://github.com/Shinigami92)
- [`@prettier/plugin-ruby`](https://github.com/prettier/plugin-ruby)
- [`@prettier/plugin-swift`](https://github.com/prettier/plugin-swift)
- [`@prettier/plugin-xml`](https://github.com/prettier/plugin-xml)
## Community Plugins
@@ -50,7 +49,6 @@ Providing at least one path to `--plugin-search-dir`/`pluginSearchDirs` turns of
- [`prettier-plugin-go-template`](https://github.com/NiklasPor/prettier-plugin-go-template) by [**@NiklasPor**](https://github.com/NiklasPor)
- [`prettier-plugin-java`](https://github.com/jhipster/prettier-java) by [**@JHipster**](https://github.com/jhipster)
- [`prettier-plugin-kotlin`](https://github.com/Angry-Potato/prettier-plugin-kotlin) by [**@Angry-Potato**](https://github.com/Angry-Potato)
- [`prettier-plugin-pg`](https://github.com/benjie/prettier-plugin-pg) by [**@benjie**](https://github.com/benjie)
- [`prettier-plugin-properties`](https://github.com/eemeli/prettier-plugin-properties) by [**@eemeli**](https://github.com/eemeli)
- [`prettier-plugin-solidity`](https://github.com/prettier-solidity/prettier-plugin-solidity) by [**@mattiaerre**](https://github.com/mattiaerre)
- [`prettier-plugin-svelte`](https://github.com/UnwrittenFun/prettier-plugin-svelte) by [**@UnwrittenFun**](https://github.com/UnwrittenFun)
@@ -178,22 +176,48 @@ function print(
path: AstPath,
options: object,
// Recursively print a child node
print: (path: AstPath) => Doc
print: (selector?: string | number | Array<string | number> | AstPath) => Doc
): Doc;
```
The `print` function is passed a `path` object, which can be used to access nodes in the AST via `path.getValue()`. It is also passed a persistent `options` object (which contains global options and which a plugin may mutate), and a `print` function used for making recursive calls. A basic `print` function might be as follows:
The `print` function is passed the following parameters:
- **`path`**: An object, which can be used to access nodes in the AST. It’s a stack-like data structure that maintains the current state of the recursion. It is called “path” because it represents the path to the current node from the root of the AST. The current node is returned by `path.getValue()`.
- **`options`**: A persistent object, which contains global options and which a plugin may mutate to store contextual data.
- **`print`**: A callback for printing sub-nodes. This function contains the core printing logic that consists of steps whose implementation is provided by plugins. In particular, it calls the printer’s `print` function and passes itself to it. Thus, the two `print` functions – the one from the core and the one from the plugin – call each other while descending down the AST recursively.
Here’s a simplified example to give an idea of what a typical implementation of `print` looks like:
```js
const { builders } = require("prettier").doc;
const {
builders: { group, indent, join, line, softline },
} = require("prettier").doc;
function print(path, options, print) {
const node = path.getValue();
if (Array.isArray(node)) {
return builders.concat(path.map(print));
switch (node.type) {
case "list":
return group([
"(",
indent([softline, join(line, path.map(print, "elements"))]),
softline,
")",
]);
case "pair":
return group([
"(",
indent([softline, print("left"), line, ". ", print("right")]),
softline,
")",
]);
case "symbol":
return node.name;
}
return node.value;
throw new Error(`Unknown node type: ${node.type}`);
}
```
@@ -208,7 +232,7 @@ function embed(
// Path to the current AST node
path: AstPath,
// Print a node with the current printer
print: (path: AstPath) => Doc,
print: (selector?: string | number | Array<string | number> | AstPath) => Doc,
// Parse and print some text using a different parser.
// You should set `options.parser` to specify which parser to use.
textToDoc: (text: string, options: object) => Doc,
+3 -3
View File
@@ -15,7 +15,7 @@ _Make sure Prettier is installed and is in your [`devDependencies`](https://docs
npx mrm lint-staged
```
This will install [husky](https://github.com/typicode/husky) and [lint-staged](https://github.com/okonet/lint-staged), then add a configuration to the project’s `package.json` that will automatically format supported files in a pre-commit hook.
This will install [simple-git-hooks](https://github.com/toplenboren/simple-git-hooks) and [lint-staged](https://github.com/okonet/lint-staged), then add a configuration to the project’s `package.json` that will automatically format supported files in a pre-commit hook.
Read more at the [lint-staged](https://github.com/okonet/lint-staged#configuration) repo.
@@ -119,11 +119,11 @@ Alternately you can save this script as `.git/hooks/pre-commit` and give it exec
```sh
#!/bin/sh
FILES=$(git diff --cached --name-only --diff-filter=ACMR "*.js" "*.jsx" | sed 's| |\\ |g')
FILES=$(git diff --cached --name-only --diff-filter=ACMR | sed 's| |\\ |g')
[ -z "$FILES" ] && exit 0
# Prettify all selected files
echo "$FILES" | xargs ./node_modules/.bin/prettier --write
echo "$FILES" | xargs ./node_modules/.bin/prettier --ignore-unknown --write
# Add back the modified/prettified files to staging
echo "$FILES" | xargs git add
+23 -23
View File
@@ -20,12 +20,12 @@
"bin"
],
"dependencies": {
"@angular/compiler": "11.2.4",
"@angular/compiler": "11.2.7",
"@babel/code-frame": "7.12.13",
"@babel/parser": "7.13.9",
"@glimmer/syntax": "0.77.1",
"@babel/parser": "7.13.11",
"@glimmer/syntax": "0.77.6",
"@iarna/toml": "2.2.5",
"@typescript-eslint/typescript-estree": "4.16.1",
"@typescript-eslint/typescript-estree": "4.19.0",
"angular-estree-parser": "2.3.0",
"angular-html-parser": "1.7.1",
"camelcase": "6.2.0",
@@ -43,9 +43,9 @@
"fast-glob": "3.2.5",
"fast-json-stable-stringify": "2.1.0",
"find-parent-dir": "0.3.0",
"flow-parser": "0.145.0",
"flow-parser": "0.147.0",
"get-stdin": "8.0.0",
"globby": "11.0.2",
"globby": "11.0.3",
"graphql": "15.5.0",
"html-element-attributes": "2.3.0",
"html-styles": "1.0.0",
@@ -58,7 +58,7 @@
"lines-and-columns": "1.1.6",
"linguist-languages": "7.13.0",
"lodash": "4.17.21",
"mem": "8.0.0",
"mem": "8.1.0",
"meriyah": "4.1.5",
"minimatch": "3.0.4",
"minimist": "1.2.5",
@@ -77,7 +77,7 @@
"remark-math": "3.0.1",
"remark-parse": "8.0.3",
"resolve": "1.20.0",
"semver": "7.3.4",
"semver": "7.3.5",
"string-width": "4.2.2",
"strip-ansi": "6.0.0",
"typescript": "4.2.3",
@@ -88,17 +88,17 @@
"yaml-unist-parser": "1.3.1"
},
"devDependencies": {
"@babel/core": "7.13.8",
"@babel/preset-env": "7.13.9",
"@babel/types": "7.13.0",
"@glimmer/reference": "0.77.1",
"@babel/core": "7.13.13",
"@babel/preset-env": "7.13.12",
"@babel/types": "7.13.13",
"@glimmer/reference": "0.77.6",
"@rollup/plugin-alias": "3.1.2",
"@rollup/plugin-babel": "5.3.0",
"@rollup/plugin-commonjs": "16.0.0",
"@rollup/plugin-commonjs": "18.0.0",
"@rollup/plugin-json": "4.1.0",
"@rollup/plugin-node-resolve": "11.2.0",
"@rollup/plugin-replace": "2.4.1",
"@types/estree": "0.0.46",
"@rollup/plugin-node-resolve": "11.2.1",
"@rollup/plugin-replace": "2.4.2",
"@types/estree": "0.0.47",
"@types/node": "14.14.0",
"babel-jest": "26.6.3",
"babel-loader": "8.2.2",
@@ -106,14 +106,14 @@
"builtin-modules": "3.2.0",
"cross-env": "7.0.3",
"cspell": "4.2.8",
"eslint": "7.21.0",
"eslint": "7.23.0",
"eslint-config-prettier": "8.1.0",
"eslint-formatter-friendly": "7.0.0",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-jest": "24.1.8",
"eslint-plugin-jest": "24.3.2",
"eslint-plugin-prettier-internal-rules": "link:scripts/tools/eslint-plugin-prettier-internal-rules",
"eslint-plugin-react": "7.22.0",
"eslint-plugin-unicorn": "28.0.2",
"eslint-plugin-react": "7.23.1",
"eslint-plugin-unicorn": "29.0.0",
"execa": "5.0.0",
"jest": "26.6.3",
"jest-snapshot-serializer-ansi": "1.0.0",
@@ -124,13 +124,13 @@
"prettier": "2.2.1",
"pretty-bytes": "5.6.0",
"rimraf": "3.0.2",
"rollup": "2.40.0",
"rollup-plugin-polyfill-node": "0.6.1",
"rollup": "2.43.1",
"rollup-plugin-polyfill-node": "0.6.2",
"rollup-plugin-terser": "7.0.2",
"shelljs": "0.8.4",
"snapshot-diff": "0.8.1",
"synchronous-promise": "2.0.15",
"tempy": "1.0.0"
"tempy": "1.0.1"
},
"scripts": {
"prepublishOnly": "echo \"Error: must publish from dist/\" && exit 1",
+1 -1
View File
@@ -37,7 +37,7 @@ const categories = [
{ dir: "vue", title: "Vue" },
{ dir: "angular", title: "Angular" },
{ dir: "lwc", title: "LWC" },
{ dir: "handlebars", title: "Handlebars (alpha)" },
{ dir: "handlebars", title: "Ember / Handlebars" },
{ dir: "graphql", title: "GraphQL" },
{ dir: "markdown", title: "Markdown" },
{ dir: "mdx", title: "MDX" },
@@ -0,0 +1,72 @@
"use strict";
const selector = [
"MemberExpression",
"[computed=true]",
"[optional=false]",
'[property.type="BinaryExpression"]',
'[property.operator="-"]',
'[property.left.type="MemberExpression"]',
"[property.left.optional=false]",
"[property.left.computed=false]",
'[property.left.property.type="Identifier"]',
'[property.left.property.name="length"]',
'[property.right.type="Literal"]',
`:not(${[
"AssignmentExpression > .left",
"UpdateExpression > .argument",
// Ignore `getPenultimate` and `getLast` function self
'VariableDeclarator[id.name="getPenultimate"] > ArrowFunctionExpression.init *',
'VariableDeclarator[id.name="getLast"] > ArrowFunctionExpression.init *',
].join(", ")})`,
].join("");
const messageId = "consistent-negative-index-access";
module.exports = {
meta: {
type: "suggestion",
docs: {
url:
"https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/consistent-negative-index-access.js",
},
messages: {
[messageId]: "Prefer `{{method}}(…)` over `…[….length - {{index}}]`.",
},
fixable: "code",
},
create(context) {
const sourceCode = context.getSourceCode();
return {
[selector](node) {
const { value: index } = node.property.right;
if (index !== 1 && index !== 2) {
return;
}
const { object } = node;
const lengthObject = node.property.left.object;
const objectText = sourceCode.getText(object);
// Simply use text to compare object
if (sourceCode.getText(lengthObject) !== objectText) {
return;
}
const method = ["getLast", "getPenultimate"][index - 1];
context.report({
node,
messageId,
data: {
index,
method,
},
fix: (fixer) => fixer.replaceText(node, `${method}(${objectText})`),
});
},
};
},
};
@@ -3,12 +3,15 @@
module.exports = {
rules: {
"better-parent-property-check-in-needs-parens": require("./better-parent-property-check-in-needs-parens"),
"consistent-negative-index-access": require("./consistent-negative-index-access"),
"directly-loc-start-end": require("./directly-loc-start-end"),
"flat-ast-path-call": require("./flat-ast-path-call"),
"jsx-identifier-case": require("./jsx-identifier-case"),
"no-doc-builder-concat": require("./no-doc-builder-concat"),
"no-empty-flat-contents-for-if-break": require("./no-empty-flat-contents-for-if-break"),
"no-identifier-n": require("./no-identifier-n"),
"no-node-comments": require("./no-node-comments"),
"no-unnecessary-ast-path-call": require("./no-unnecessary-ast-path-call"),
"prefer-ast-path-each": require("./prefer-ast-path-each"),
"prefer-indent-if-break": require("./prefer-indent-if-break"),
"prefer-is-non-empty-array": require("./prefer-is-non-empty-array"),
@@ -0,0 +1,91 @@
"use strict";
// eslint-disable-next-line import/no-extraneous-dependencies
const { findVariable } = require("eslint-utils");
const ERROR = "error";
const SUGGESTION = "suggestion";
const selector = [
"Identifier",
'[name="n"]',
`:not(${[
"MemberExpression[computed=false] > .property",
"Property[shorthand=false][computed=false] > .key",
].join(", ")})`,
].join("");
module.exports = {
meta: {
type: "suggestion",
docs: {
url:
"https://github.com/prettier/prettier/blob/main/scripts/eslint-plugin-prettier-internal-rules/no-identifier-n.js",
},
messages: {
[ERROR]: "Please rename variable 'n'.",
[SUGGESTION]: "Rename to `node`.",
},
fixable: "code",
},
create(context) {
const variables = new Map();
return {
[selector](node) {
const scope = context.getScope();
const variable = findVariable(scope, node);
/* istanbul ignore next */
if (!variable) {
throw new Error("Unexpected case.");
}
if (!variables.has(variable)) {
variables.set(variable, { fixable: true });
}
const data = variables.get(variable);
if (!data.fixable) {
return;
}
const nodeVariable = findVariable(scope, "node");
if (nodeVariable) {
data.fixable = false;
}
},
"Program:exit"() {
for (const [variable, { fixable }] of variables.entries()) {
const [node] = variable.identifiers;
const fix = function* (fixer) {
const identifiers = new Set([
...variable.identifiers,
...variable.references.map((reference) => reference.identifier),
]);
for (const identifier of identifiers) {
const { parent } = identifier;
if (
parent &&
parent.type === "Property" &&
parent.shorthand &&
parent.key === identifier
) {
yield fixer.replaceText(identifier, "n: node");
} else {
yield fixer.replaceText(identifier, "node");
}
}
};
const problem = { node, messageId: ERROR };
if (fixable) {
problem.fix = fix;
} else {
problem.suggest = [{ messageId: SUGGESTION, fix }];
}
context.report(problem);
}
},
};
},
};
@@ -0,0 +1,57 @@
"use strict";
const selector = [
"CallExpression",
"[optional=false]",
'[callee.type="MemberExpression"]',
"[callee.computed=false]",
"[callee.optional=false]",
'[callee.property.type="Identifier"]',
'[callee.property.name="call"]',
"[arguments.length=1]",
'[arguments.0.type!="SpreadElement"]',
].join("");
const messageId = "no-unnecessary-ast-path-call";
module.exports = {
meta: {
type: "suggestion",
docs: {
url:
"https://github.com/prettier/prettier/blob/main/scripts/eslint-plugin-prettier-internal-rules/no-unnecessary-ast-path-call.js",
},
messages: {
[messageId]: "Do not use `AstPath.call()` with one argument.",
},
fixable: "code",
},
create(context) {
const sourceCode = context.getSourceCode();
return {
[selector](node) {
const problem = {
node,
messageId,
};
const [callback] = node.arguments;
// Don't fix to IIFE
if (
callback.type !== "ArrowFunctionExpression" &&
callback.type !== "FunctionExpression"
) {
problem.fix = function (fixer) {
const callbackText = sourceCode.getText(callback);
const astPathText = sourceCode.getText(node.callee.object);
return fixer.replaceText(node, `${callbackText}(${astPathText})`);
};
}
context.report(problem);
},
};
},
};
@@ -53,6 +53,50 @@ test("better-parent-property-check-in-needs-parens", {
})),
});
test("consistent-negative-index-access", {
valid: [
"getLast(foo)",
"getPenultimate(foo)",
"foo[foo.length]",
"foo[foo.length - 3]",
"foo[foo.length + 1]",
"foo[foo.length + -1]",
"foo[foo.length * -1]",
"foo.length - 1",
"foo?.[foo.length - 1]",
"foo[foo?.length - 1]",
"foo[foo['length'] - 1]",
"foo[bar.length - 1]",
"foo.bar[foo. bar.length - 1]",
"foo[foo.length - 1]++",
"--foo[foo.length - 1]",
"foo[foo.length - 1] += 1",
"foo[foo.length - 1] = 1",
],
invalid: [
{
code: "foo[foo.length - 1]",
output: "getLast(foo)",
errors: 1,
},
{
code: "foo[foo.length - 2]",
output: "getPenultimate(foo)",
errors: 1,
},
{
code: "foo[foo.length - 0b10]",
output: "getPenultimate(foo)",
errors: 1,
},
{
code: "foo()[foo().length - 1]",
output: "getLast(foo())",
errors: 1,
},
],
});
test("directly-loc-start-end", {
valid: [],
invalid: [
@@ -81,6 +125,7 @@ test("flat-ast-path-call", {
'path.call((childPath) => childPath.call(print), "a")',
'path.call((childPath) => notChildPath.call(print), "a")',
'path.call(functionReference, "a")',
'path.call((childPath) => notChildPath.call(print, "b"), "a")',
// Only check `arrow function`
'path.call((childPath) => {return childPath.call(print, "b")}, "a")',
'path.call(function(childPath) {return childPath.call(print, "b")}, "a")',
@@ -137,6 +182,69 @@ test("no-doc-builder-concat", {
],
});
test("no-identifier-n", {
valid: ["const a = {n: 1}", "const m = 1", "a.n = 1"],
invalid: [
{
code: "const n = 1; alet(n)",
output: "const node = 1; alet(node)",
errors: 1,
},
{
code: "const n = 1; alert({n})",
output: "const node = 1; alert({n: node})",
errors: 1,
},
{
code: "const {n} = 1; alert(n)",
output: "const {n: node} = 1; alert(node)",
errors: 1,
},
{
code: outdent`
const n = 1;
function a(node) {
alert(n, node)
}
function b() {
alert(n)
}
`,
output: outdent`
const n = 1;
function a(node) {
alert(n, node)
}
function b() {
alert(n)
}
`,
errors: [
{
suggestions: [
{
output: outdent`
const node = 1;
function a(node) {
alert(node, node)
}
function b() {
alert(node)
}
`,
},
],
},
],
},
{
code: "const n = 1;const node = 2;",
output: "const n = 1;const node = 2;",
errors: [{ suggestions: [{ output: "const node = 1;const node = 2;" }] }],
},
],
});
test("no-node-comments", {
valid: [
"const comments = node.notComments",
@@ -303,3 +411,28 @@ test("no-empty-flat-contents-for-if-break", {
},
],
});
test("no-unnecessary-ast-path-call", {
valid: [
"call(foo)",
'foo["call"](bar)',
"foo.call?.(bar)",
"foo?.call(bar)",
"foo.call(bar, name)",
"foo.notCall(bar)",
"foo.call(...bar)",
"foo.call()",
],
invalid: [
{
code: "foo.call(bar)",
output: "bar(foo)",
errors: 1,
},
{
code: "foo.call(() => bar)",
output: "foo.call(() => bar)",
errors: 1,
},
],
});
+3 -3
View File
@@ -69,16 +69,16 @@ function indent(contents) {
}
/**
* @param {number | string} n
* @param {number | string} widthOrString
* @param {Doc} contents
* @returns Doc
*/
function align(n, contents) {
function align(widthOrString, contents) {
if (process.env.NODE_ENV !== "production") {
assertDoc(contents);
}
return { type: "align", contents, n };
return { type: "align", contents, n: widthOrString };
}
/**
+15 -15
View File
@@ -19,26 +19,27 @@ function makeIndent(ind, options) {
return generateInd(ind, { type: "indent" }, options);
}
function makeAlign(indent, n, options) {
if (n === Number.NEGATIVE_INFINITY) {
function makeAlign(indent, widthOrDoc, options) {
if (widthOrDoc === Number.NEGATIVE_INFINITY) {
return indent.root || rootIndent();
}
if (n < 0) {
if (widthOrDoc < 0) {
return generateInd(indent, { type: "dedent" }, options);
}
if (!n) {
if (!widthOrDoc) {
return indent;
}
if (n.type === "root") {
if (widthOrDoc.type === "root") {
return { ...indent, root: indent };
}
const alignType = typeof n === "string" ? "stringAlign" : "numberAlign";
const alignType =
typeof widthOrDoc === "string" ? "stringAlign" : "numberAlign";
return generateInd(indent, { type: alignType, n }, options);
return generateInd(indent, { type: alignType, n: widthOrDoc }, options);
}
function generateInd(ind, newPart, options) {
@@ -129,15 +130,15 @@ function trim(out) {
// Trim whitespace at the end of line
while (
out.length > 0 &&
typeof out[out.length - 1] === "string" &&
/^[\t ]*$/.test(out[out.length - 1])
typeof getLast(out) === "string" &&
/^[\t ]*$/.test(getLast(out))
) {
trimCount += out.pop().length;
}
if (out.length > 0 && typeof out[out.length - 1] === "string") {
const trimmed = out[out.length - 1].replace(/[\t ]*$/, "");
trimCount += out[out.length - 1].length - trimmed.length;
if (out.length > 0 && typeof getLast(out) === "string") {
const trimmed = getLast(out).replace(/[\t ]*$/, "");
trimCount += getLast(out).length - trimmed.length;
out[out.length - 1] = trimmed;
}
@@ -352,8 +353,7 @@ function printDocToString(doc, options) {
// group has these, we need to manually go through
// these states and find the first one that fits.
if (doc.expandedStates) {
const mostExpanded =
doc.expandedStates[doc.expandedStates.length - 1];
const mostExpanded = getLast(doc.expandedStates);
if (doc.break) {
cmds.push([ind, MODE_BREAK, mostExpanded]);
@@ -387,7 +387,7 @@ function printDocToString(doc, options) {
}
if (doc.id) {
groupModeMap[doc.id] = cmds[cmds.length - 1][1];
groupModeMap[doc.id] = getLast(cmds)[1];
}
break;
// Fills each line with as much code as possible before moving to a new
+5 -8
View File
@@ -1,5 +1,5 @@
"use strict";
const getLast = require("../utils/get-last");
const { literalline } = require("./doc-builders");
const isConcat = (doc) => Array.isArray(doc) || (doc && doc.type === "concat");
@@ -128,7 +128,7 @@ function willBreak(doc) {
function breakParentGroup(groupStack) {
if (groupStack.length > 0) {
const parentGroup = groupStack[groupStack.length - 1];
const parentGroup = getLast(groupStack);
// Breaks are not propagated through conditional groups because
// the user is expected to manually handle what breaks.
if (!parentGroup.expandedStates && !parentGroup.break) {
@@ -210,7 +210,7 @@ function stripDocTrailingHardlineFromDoc(doc) {
}
if (parts.length > 0) {
const lastPart = stripDocTrailingHardlineFromDoc(parts[parts.length - 1]);
const lastPart = stripDocTrailingHardlineFromDoc(getLast(parts));
parts[parts.length - 1] = lastPart;
}
return Array.isArray(doc) ? parts : { ...doc, parts };
@@ -289,10 +289,7 @@ function cleanDocFn(doc) {
const [currentPart, ...restParts] = isConcat(part)
? getDocParts(part)
: [part];
if (
typeof currentPart === "string" &&
typeof parts[parts.length - 1] === "string"
) {
if (typeof currentPart === "string" && typeof getLast(parts) === "string") {
parts[parts.length - 1] += currentPart;
} else {
parts.push(currentPart);
@@ -335,7 +332,7 @@ function normalizeParts(parts) {
if (
newParts.length > 0 &&
typeof newParts[newParts.length - 1] === "string" &&
typeof getLast(newParts) === "string" &&
typeof part === "string"
) {
newParts[newParts.length - 1] += part;
+4 -3
View File
@@ -1,6 +1,7 @@
"use strict";
const createError = require("../common/parser-create-error");
const getLast = require("../utils/get-last");
const parseFrontMatter = require("../utils/front-matter/parse");
const { hasPragma } = require("./pragma");
const {
@@ -43,7 +44,7 @@ function parseValueNode(valueNode, options) {
options.parser === "scss" &&
node.type === "number" &&
node.unit === ".." &&
node.value[node.value.length - 1] === "."
getLast(node.value) === "."
) {
// Work around postcss bug parsing `50...` as `50.` with unit `..`
// Set the unit to `...` to "accidentally" have arbitrary arguments work in the same way that cases where the node already had a unit work.
@@ -115,11 +116,11 @@ function parseValueNode(valueNode, options) {
}
commaGroupStack.pop();
commaGroup = commaGroupStack[commaGroupStack.length - 1];
commaGroup = getLast(commaGroupStack);
commaGroup.groups.push(parenGroup);
parenGroupStack.pop();
parenGroup = parenGroupStack[parenGroupStack.length - 1];
parenGroup = getLast(parenGroupStack);
} else if (node.type === "comma") {
parenGroup.groups.push(commaGroup);
commaGroup = {
+22 -21
View File
@@ -1,5 +1,6 @@
"use strict";
const getLast = require("../utils/get-last");
const {
printNumber,
printString,
@@ -112,7 +113,7 @@ function genericPrint(path, options, print) {
}
case "css-rule": {
return [
path.call(print, "selector"),
print("selector"),
node.important ? " !important" : "",
node.nodes
? [
@@ -144,8 +145,8 @@ function genericPrint(path, options, print) {
typeof node.value === "string" && /^ *$/.test(node.value);
let value = hasComposesNode(node)
? removeLines(path.call(print, "value"))
: path.call(print, "value");
? removeLines(print("value"))
: print("value");
if (!isColon && lastLineHasInlineComment(trimmedBetween)) {
value = indent([hardline, dedent(value)]);
@@ -158,7 +159,7 @@ function genericPrint(path, options, print) {
trimmedBetween,
node.extend || isValueAllSpace ? "" : " ",
options.parser === "less" && node.extend && node.selector
? ["extend(", path.call(print, "selector"), ")"]
? ["extend(", print("selector"), ")"]
: "",
value,
node.raws.important
@@ -202,7 +203,7 @@ function genericPrint(path, options, print) {
if (options.parser === "less") {
if (node.mixin) {
return [
path.call(print, "selector"),
print("selector"),
node.important ? " !important" : "",
isTemplatePlaceholderNodeWithoutSemiColon ? "" : ";",
];
@@ -211,7 +212,7 @@ function genericPrint(path, options, print) {
if (node.function) {
return [
node.name,
path.call(print, "params"),
print("params"),
isTemplatePlaceholderNodeWithoutSemiColon ? "" : ";",
];
}
@@ -221,7 +222,7 @@ function genericPrint(path, options, print) {
"@",
node.name,
": ",
node.value ? path.call(print, "value") : "",
node.value ? print("value") : "",
node.raws.between.trim() ? node.raws.between.trim() + " " : "",
node.nodes
? [
@@ -267,14 +268,14 @@ function genericPrint(path, options, print) {
? hardline
: " "
: " ",
path.call(print, "params"),
print("params"),
]
: "",
node.selector ? indent([" ", path.call(print, "selector")]) : "",
node.selector ? indent([" ", print("selector")]) : "",
node.value
? group([
" ",
path.call(print, "value"),
print("value"),
isSCSSControlDirectiveNode(node, options)
? hasParensAroundNode(node)
? " "
@@ -319,7 +320,7 @@ function genericPrint(path, options, print) {
if (node.type === "media-query" && node.value === "") {
return;
}
parts.push(childPath.call(print));
parts.push(print());
}, "nodes");
return group(indent(join(line, parts)));
@@ -512,7 +513,7 @@ function genericPrint(path, options, print) {
// postcss-values-parser
case "value-value":
case "value-root": {
return path.call(print, "group");
return print("group");
}
case "value-comment": {
return options.originalText.slice(locStart(node), locEnd(node));
@@ -842,9 +843,9 @@ function genericPrint(path, options, print) {
node.groups[0].groups[0].value.startsWith("data:")))
) {
return [
node.open ? path.call(print, "open") : "",
node.open ? print("open") : "",
join(",", path.map(print, "groups")),
node.close ? path.call(print, "close") : "",
node.close ? print("close") : "",
];
}
@@ -864,20 +865,20 @@ function genericPrint(path, options, print) {
const isSCSSMapItem = isSCSSMapItemNode(path, options);
const lastItem = node.groups[node.groups.length - 1];
const lastItem = getLast(node.groups);
const isLastItemComment = lastItem && lastItem.type === "value-comment";
const isKey = isKeyInValuePairNode(node, parentNode);
const printed = group(
[
node.open ? path.call(print, "open") : "",
node.open ? print("open") : "",
indent([
softline,
join(
[",", line],
path.map((childPath) => {
const node = childPath.getValue();
const printed = print(childPath);
const printed = print();
// Key/Value pair in open paren already indented
if (
@@ -907,7 +908,7 @@ function genericPrint(path, options, print) {
: ""
),
softline,
node.close ? path.call(print, "close") : "",
node.close ? print("close") : "",
],
{
shouldBreak: isSCSSMapItem && !isKey,
@@ -922,7 +923,7 @@ function genericPrint(path, options, print) {
insideAtRuleNode(path, "supports") && isMediaAndSupportsKeywords(node)
? " "
: "",
path.call(print, "group"),
print("group"),
];
}
case "value-paren": {
@@ -950,7 +951,7 @@ function genericPrint(path, options, print) {
// Don't add spaces on escaped colon `:`, e.g: grid-template-rows: [row-1-00\:00] auto;
(prevNode &&
typeof prevNode.value === "string" &&
prevNode.value[prevNode.value.length - 1] === "\\") ||
getLast(prevNode.value) === "\\") ||
// Don't add spaces on `:` in `url` function (i.e. `url(fbglyph: cross-outline, fig-white)`)
insideValueFunctionNode(path, "url")
? ""
@@ -997,7 +998,7 @@ function printNodeSequence(path, options, print) {
options.originalText.slice(locStart(childNode), locEnd(childNode))
);
} else {
parts.push(pathChild.call(print));
parts.push(print());
}
if (i !== nodes.length - 1) {
+120 -114
View File
@@ -8,20 +8,20 @@ const { insertPragma } = require("./pragma");
const { locStart, locEnd } = require("./loc");
function genericPrint(path, options, print) {
const n = path.getValue();
if (!n) {
const node = path.getValue();
if (!node) {
return "";
}
if (typeof n === "string") {
return n;
if (typeof node === "string") {
return node;
}
switch (n.kind) {
switch (node.kind) {
case "Document": {
const parts = [];
path.each((pathChild, index, definitions) => {
parts.push(pathChild.call(print));
parts.push(print());
if (index !== definitions.length - 1) {
parts.push(hardline);
if (
@@ -34,12 +34,12 @@ function genericPrint(path, options, print) {
return [...parts, hardline];
}
case "OperationDefinition": {
const hasOperation = options.originalText[locStart(n)] !== "{";
const hasName = Boolean(n.name);
const hasOperation = options.originalText[locStart(node)] !== "{";
const hasName = Boolean(node.name);
return [
hasOperation ? n.operation : "",
hasOperation && hasName ? [" ", path.call(print, "name")] : "",
isNonEmptyArray(n.variableDefinitions)
hasOperation ? node.operation : "",
hasOperation && hasName ? [" ", print("name")] : "",
isNonEmptyArray(node.variableDefinitions)
? group([
"(",
indent([
@@ -53,16 +53,16 @@ function genericPrint(path, options, print) {
")",
])
: "",
printDirectives(path, print, n),
n.selectionSet ? (!hasOperation && !hasName ? "" : " ") : "",
path.call(print, "selectionSet"),
printDirectives(path, print, node),
node.selectionSet ? (!hasOperation && !hasName ? "" : " ") : "",
print("selectionSet"),
];
}
case "FragmentDefinition": {
return [
"fragment ",
path.call(print, "name"),
isNonEmptyArray(n.variableDefinitions)
print("name"),
isNonEmptyArray(node.variableDefinitions)
? group([
"(",
indent([
@@ -77,10 +77,10 @@ function genericPrint(path, options, print) {
])
: "",
" on ",
path.call(print, "typeCondition"),
printDirectives(path, print, n),
print("typeCondition"),
printDirectives(path, print, node),
" ",
path.call(print, "selectionSet"),
print("selectionSet"),
];
}
case "SelectionSet": {
@@ -102,9 +102,9 @@ function genericPrint(path, options, print) {
}
case "Field": {
return group([
n.alias ? [path.call(print, "alias"), ": "] : "",
path.call(print, "name"),
n.arguments.length > 0
node.alias ? [print("alias"), ": "] : "",
print("name"),
node.arguments.length > 0
? group([
"(",
indent([
@@ -121,43 +121,43 @@ function genericPrint(path, options, print) {
")",
])
: "",
printDirectives(path, print, n),
n.selectionSet ? " " : "",
path.call(print, "selectionSet"),
printDirectives(path, print, node),
node.selectionSet ? " " : "",
print("selectionSet"),
]);
}
case "Name": {
return n.value;
return node.value;
}
case "StringValue": {
if (n.block) {
if (node.block) {
return [
'"""',
hardline,
join(hardline, n.value.replace(/"""/g, "\\$&").split("\n")),
join(hardline, node.value.replace(/"""/g, "\\$&").split("\n")),
hardline,
'"""',
];
}
return [
'"',
n.value.replace(/["\\]/g, "\\$&").replace(/\n/g, "\\n"),
node.value.replace(/["\\]/g, "\\$&").replace(/\n/g, "\\n"),
'"',
];
}
case "IntValue":
case "FloatValue":
case "EnumValue": {
return n.value;
return node.value;
}
case "BooleanValue": {
return n.value ? "true" : "false";
return node.value ? "true" : "false";
}
case "NullValue": {
return "null";
}
case "Variable": {
return ["$", path.call(print, "name")];
return ["$", print("name")];
}
case "ListValue": {
return group([
@@ -173,26 +173,29 @@ function genericPrint(path, options, print) {
case "ObjectValue": {
return group([
"{",
options.bracketSpacing && n.fields.length > 0 ? " " : "",
options.bracketSpacing && node.fields.length > 0 ? " " : "",
indent([
softline,
join([ifBreak("", ", "), softline], path.map(print, "fields")),
]),
softline,
ifBreak("", options.bracketSpacing && n.fields.length > 0 ? " " : ""),
ifBreak(
"",
options.bracketSpacing && node.fields.length > 0 ? " " : ""
),
"}",
]);
}
case "ObjectField":
case "Argument": {
return [path.call(print, "name"), ": ", path.call(print, "value")];
return [print("name"), ": ", print("value")];
}
case "Directive": {
return [
"@",
path.call(print, "name"),
n.arguments.length > 0
print("name"),
node.arguments.length > 0
? group([
"(",
indent([
@@ -213,32 +216,32 @@ function genericPrint(path, options, print) {
}
case "NamedType": {
return path.call(print, "name");
return print("name");
}
case "VariableDefinition": {
return [
path.call(print, "variable"),
print("variable"),
": ",
path.call(print, "type"),
n.defaultValue ? [" = ", path.call(print, "defaultValue")] : "",
printDirectives(path, print, n),
print("type"),
node.defaultValue ? [" = ", print("defaultValue")] : "",
printDirectives(path, print, node),
];
}
case "ObjectTypeExtension":
case "ObjectTypeDefinition": {
return [
path.call(print, "description"),
n.description ? hardline : "",
n.kind === "ObjectTypeExtension" ? "extend " : "",
print("description"),
node.description ? hardline : "",
node.kind === "ObjectTypeExtension" ? "extend " : "",
"type ",
path.call(print, "name"),
n.interfaces.length > 0
print("name"),
node.interfaces.length > 0
? [" implements ", ...printInterfaces(path, options, print)]
: "",
printDirectives(path, print, n),
n.fields.length > 0
printDirectives(path, print, node),
node.fields.length > 0
? [
" {",
indent([
@@ -260,10 +263,10 @@ function genericPrint(path, options, print) {
case "FieldDefinition": {
return [
path.call(print, "description"),
n.description ? hardline : "",
path.call(print, "name"),
n.arguments.length > 0
print("description"),
node.description ? hardline : "",
print("name"),
node.arguments.length > 0
? group([
"(",
indent([
@@ -281,19 +284,19 @@ function genericPrint(path, options, print) {
])
: "",
": ",
path.call(print, "type"),
printDirectives(path, print, n),
print("type"),
printDirectives(path, print, node),
];
}
case "DirectiveDefinition": {
return [
path.call(print, "description"),
n.description ? hardline : "",
print("description"),
node.description ? hardline : "",
"directive ",
"@",
path.call(print, "name"),
n.arguments.length > 0
print("name"),
node.arguments.length > 0
? group([
"(",
indent([
@@ -310,7 +313,7 @@ function genericPrint(path, options, print) {
")",
])
: "",
n.repeatable ? " repeatable" : "",
node.repeatable ? " repeatable" : "",
" on ",
join(" | ", path.map(print, "locations")),
];
@@ -319,14 +322,14 @@ function genericPrint(path, options, print) {
case "EnumTypeExtension":
case "EnumTypeDefinition": {
return [
path.call(print, "description"),
n.description ? hardline : "",
n.kind === "EnumTypeExtension" ? "extend " : "",
print("description"),
node.description ? hardline : "",
node.kind === "EnumTypeExtension" ? "extend " : "",
"enum ",
path.call(print, "name"),
printDirectives(path, print, n),
print("name"),
printDirectives(path, print, node),
n.values.length > 0
node.values.length > 0
? [
" {",
indent([
@@ -348,35 +351,35 @@ function genericPrint(path, options, print) {
case "EnumValueDefinition": {
return [
path.call(print, "description"),
n.description ? hardline : "",
path.call(print, "name"),
printDirectives(path, print, n),
print("description"),
node.description ? hardline : "",
print("name"),
printDirectives(path, print, node),
];
}
case "InputValueDefinition": {
return [
path.call(print, "description"),
n.description ? (n.description.block ? hardline : line) : "",
path.call(print, "name"),
print("description"),
node.description ? (node.description.block ? hardline : line) : "",
print("name"),
": ",
path.call(print, "type"),
n.defaultValue ? [" = ", path.call(print, "defaultValue")] : "",
printDirectives(path, print, n),
print("type"),
node.defaultValue ? [" = ", print("defaultValue")] : "",
printDirectives(path, print, node),
];
}
case "InputObjectTypeExtension":
case "InputObjectTypeDefinition": {
return [
path.call(print, "description"),
n.description ? hardline : "",
n.kind === "InputObjectTypeExtension" ? "extend " : "",
print("description"),
node.description ? hardline : "",
node.kind === "InputObjectTypeExtension" ? "extend " : "",
"input ",
path.call(print, "name"),
printDirectives(path, print, n),
n.fields.length > 0
print("name"),
printDirectives(path, print, node),
node.fields.length > 0
? [
" {",
indent([
@@ -399,9 +402,9 @@ function genericPrint(path, options, print) {
case "SchemaDefinition": {
return [
"schema",
printDirectives(path, print, n),
printDirectives(path, print, node),
" {",
n.operationTypes.length > 0
node.operationTypes.length > 0
? indent([
hardline,
join(
@@ -419,22 +422,22 @@ function genericPrint(path, options, print) {
}
case "OperationTypeDefinition": {
return [path.call(print, "operation"), ": ", path.call(print, "type")];
return [print("operation"), ": ", print("type")];
}
case "InterfaceTypeExtension":
case "InterfaceTypeDefinition": {
return [
path.call(print, "description"),
n.description ? hardline : "",
n.kind === "InterfaceTypeExtension" ? "extend " : "",
print("description"),
node.description ? hardline : "",
node.kind === "InterfaceTypeExtension" ? "extend " : "",
"interface ",
path.call(print, "name"),
n.interfaces.length > 0
print("name"),
node.interfaces.length > 0
? [" implements ", ...printInterfaces(path, options, print)]
: "",
printDirectives(path, print, n),
n.fields.length > 0
printDirectives(path, print, node),
node.fields.length > 0
? [
" {",
indent([
@@ -455,30 +458,30 @@ function genericPrint(path, options, print) {
}
case "FragmentSpread": {
return ["...", path.call(print, "name"), printDirectives(path, print, n)];
return ["...", print("name"), printDirectives(path, print, node)];
}
case "InlineFragment": {
return [
"...",
n.typeCondition ? [" on ", path.call(print, "typeCondition")] : "",
printDirectives(path, print, n),
node.typeCondition ? [" on ", print("typeCondition")] : "",
printDirectives(path, print, node),
" ",
path.call(print, "selectionSet"),
print("selectionSet"),
];
}
case "UnionTypeExtension":
case "UnionTypeDefinition": {
return group([
path.call(print, "description"),
n.description ? hardline : "",
print("description"),
node.description ? hardline : "",
group([
n.kind === "UnionTypeExtension" ? "extend " : "",
node.kind === "UnionTypeExtension" ? "extend " : "",
"union ",
path.call(print, "name"),
printDirectives(path, print, n),
n.types.length > 0
print("name"),
printDirectives(path, print, node),
node.types.length > 0
? [
" =",
ifBreak("", " "),
@@ -495,37 +498,40 @@ function genericPrint(path, options, print) {
case "ScalarTypeExtension":
case "ScalarTypeDefinition": {
return [
path.call(print, "description"),
n.description ? hardline : "",
n.kind === "ScalarTypeExtension" ? "extend " : "",
print("description"),
node.description ? hardline : "",
node.kind === "ScalarTypeExtension" ? "extend " : "",
"scalar ",
path.call(print, "name"),
printDirectives(path, print, n),
print("name"),
printDirectives(path, print, node),
];
}
case "NonNullType": {
return [path.call(print, "type"), "!"];
return [print("type"), "!"];
}
case "ListType": {
return ["[", path.call(print, "type"), "]"];
return ["[", print("type"), "]"];
}
default:
/* istanbul ignore next */
throw new Error("unknown graphql type: " + JSON.stringify(n.kind));
throw new Error("unknown graphql type: " + JSON.stringify(node.kind));
}
}
function printDirectives(path, print, n) {
if (n.directives.length === 0) {
function printDirectives(path, print, node) {
if (node.directives.length === 0) {
return "";
}
const printed = join(line, path.map(print, "directives"));
if (n.kind === "FragmentDefinition" || n.kind === "OperationDefinition") {
if (
node.kind === "FragmentDefinition" ||
node.kind === "OperationDefinition"
) {
return group([line, printed]);
}
@@ -536,7 +542,7 @@ function printSequence(sequencePath, options, print) {
const count = sequencePath.getValue().length;
return sequencePath.map((path, i) => {
const printed = print(path);
const printed = print();
if (
isNextLineEmpty(options.originalText, path.getValue(), locEnd) &&
+1 -1
View File
@@ -5,7 +5,7 @@ const printer = require("./printer-glimmer");
const languages = [
createLanguage(require("linguist-languages/data/Handlebars.json"), () => ({
since: null, // unreleased
since: "2.3.0",
parsers: ["glimmer"],
vscodeLanguageIds: ["handlebars"],
})),
+43 -43
View File
@@ -37,18 +37,18 @@ const NEWLINES_TO_PRESERVE_MAX = 2;
// https://github.com/glimmerjs/glimmer-vm/blob/master/packages/%40glimmer/syntax/lib/generation/print.ts
function print(path, options, print) {
const n = path.getValue();
const node = path.getValue();
/* istanbul ignore if*/
if (!n) {
if (!node) {
return "";
}
if (hasPrettierIgnore(path)) {
return options.originalText.slice(locStart(n), locEnd(n));
return options.originalText.slice(locStart(node), locEnd(node));
}
switch (n.type) {
switch (node.type) {
case "Block":
case "Program":
case "Template": {
@@ -64,13 +64,13 @@ function print(path, options, print) {
? softline
: "";
if (isVoid(n)) {
if (isVoid(node)) {
return [startingTag, escapeNextElementNode];
}
const endingTag = ["</", n.tag, ">"];
const endingTag = ["</", node.tag, ">"];
if (n.children.length === 0) {
if (node.children.length === 0) {
return [startingTag, indent(endingTag), escapeNextElementNode];
}
@@ -99,7 +99,7 @@ function print(path, options, print) {
pp &&
pp.inverse &&
pp.inverse.body.length === 1 &&
pp.inverse.body[0] === n &&
pp.inverse.body[0] === node &&
pp.inverse.body[0].path.parts[0] === "if";
if (isElseIf) {
@@ -131,18 +131,18 @@ function print(path, options, print) {
const isChildOfElementNodeAndDoesNotHaveParams =
isParentOfSomeType(path, ["ElementNode"]) &&
doesNotHaveHashParams(n) &&
doesNotHavePositionalParams(n);
doesNotHaveHashParams(node) &&
doesNotHavePositionalParams(node);
const shouldBreakOpeningMustache =
isParentOfSpecifiedTypes || isChildOfElementNodeAndDoesNotHaveParams;
return group([
printOpeningMustache(n),
printOpeningMustache(node),
shouldBreakOpeningMustache ? indent(softline) : "",
printPathAndParams(path, print),
softline,
printClosingMustache(n),
printClosingMustache(node),
]);
}
@@ -155,37 +155,37 @@ function print(path, options, print) {
]);
}
case "AttrNode": {
const isText = n.value.type === "TextNode";
const isEmptyText = isText && n.value.chars === "";
const isText = node.value.type === "TextNode";
const isEmptyText = isText && node.value.chars === "";
// If the text is empty and the value's loc start and end offsets are the
// same, there is no value for this AttrNode and it should be printed
// without the `=""`. Example: `<img data-test>` -> `<img data-test>`
if (isEmptyText && locStart(n.value) === locEnd(n.value)) {
return n.name;
if (isEmptyText && locStart(node.value) === locEnd(node.value)) {
return node.name;
}
// Let's assume quotes inside the content of text nodes are already
// properly escaped with entities, otherwise the parse wouldn't have parsed them.
const quote = isText
? chooseEnclosingQuote(options, n.value.chars).quote
: n.value.type === "ConcatStatement"
? chooseEnclosingQuote(options, node.value.chars).quote
: node.value.type === "ConcatStatement"
? chooseEnclosingQuote(
options,
n.value.parts
node.value.parts
.filter((part) => part.type === "TextNode")
.map((part) => part.chars)
.join("")
).quote
: "";
const valueDoc = path.call(print, "value");
const valueDoc = print("value");
return [
n.name,
node.name,
"=",
quote,
n.name === "class" && quote ? group(indent(valueDoc)) : valueDoc,
node.name === "class" && quote ? group(indent(valueDoc)) : valueDoc,
quote,
];
}
@@ -198,13 +198,13 @@ function print(path, options, print) {
return join(line, path.map(print, "pairs"));
}
case "HashPair": {
return [n.key, "=", path.call(print, "value")];
return [node.key, "=", print("value")];
}
case "TextNode": {
/* if `{{my-component}}` (or any text containing "{{")
* makes it to the TextNode, it means it was escaped,
* so let's print it escaped, ie.; `\{{my-component}}` */
let text = n.chars.replace(/{{/g, "\\{{");
let text = node.chars.replace(/{{/g, "\\{{");
const attrName = getCurrentAttributeName(path);
@@ -381,8 +381,8 @@ function print(path, options, print) {
];
}
case "MustacheCommentStatement": {
const start = locStart(n);
const end = locEnd(n);
const start = locStart(node);
const end = locEnd(node);
// Starts with `{{~`
const isLeftWhiteSpaceSensitive =
options.originalText.charAt(start + 2) === "~";
@@ -390,32 +390,32 @@ function print(path, options, print) {
const isRightWhitespaceSensitive =
options.originalText.charAt(end - 3) === "~";
const dashes = n.value.includes("}}") ? "--" : "";
const dashes = node.value.includes("}}") ? "--" : "";
return [
"{{",
isLeftWhiteSpaceSensitive ? "~" : "",
"!",
dashes,
n.value,
node.value,
dashes,
isRightWhitespaceSensitive ? "~" : "",
"}}",
];
}
case "PathExpression": {
return n.original;
return node.original;
}
case "BooleanLiteral": {
return String(n.value);
return String(node.value);
}
case "CommentStatement": {
return ["<!--", n.value, "-->"];
return ["<!--", node.value, "-->"];
}
case "StringLiteral": {
return printStringLiteral(n.value, options);
return printStringLiteral(node.value, options);
}
case "NumberLiteral": {
return String(n.value);
return String(node.value);
}
case "UndefinedLiteral": {
return "undefined";
@@ -426,7 +426,7 @@ function print(path, options, print) {
/* istanbul ignore next */
default:
throw new Error("unknown glimmer type: " + JSON.stringify(n.type));
throw new Error("unknown glimmer type: " + JSON.stringify(node.type));
}
}
@@ -454,13 +454,13 @@ function printStartingTag(path, print) {
function printChildren(path, options, print) {
const node = path.getValue();
const isEmpty = node.children.every((n) => isWhitespaceNode(n));
const isEmpty = node.children.every((node) => isWhitespaceNode(node));
if (options.htmlWhitespaceSensitivity === "ignore" && isEmpty) {
return "";
}
return path.map((childPath, childIndex) => {
const printedChild = print(childPath, options, print);
const printedChild = print();
if (childIndex === 0 && options.htmlWhitespaceSensitivity === "ignore") {
return [softline, printedChild];
@@ -587,14 +587,14 @@ function printCloseBlock(path, print, options) {
return [
escape,
printClosingBlockOpeningMustache(node),
path.call(print, "path"),
print("path"),
printClosingBlockClosingMustache(node),
];
}
return [
printClosingBlockOpeningMustache(node),
path.call(print, "path"),
print("path"),
printClosingBlockClosingMustache(node),
];
}
@@ -602,7 +602,7 @@ function printCloseBlock(path, print, options) {
function blockStatementHasOnlyWhitespaceInProgram(node) {
return (
isNodeOfSomeType(node, ["BlockStatement"]) &&
node.program.body.every((n) => isWhitespaceNode(n))
node.program.body.every((node) => isWhitespaceNode(node))
);
}
@@ -626,7 +626,7 @@ function printProgram(path, print, options) {
return "";
}
const program = path.call(print, "program");
const program = print("program");
if (options.htmlWhitespaceSensitivity === "ignore") {
return indent([hardline, program]);
@@ -638,7 +638,7 @@ function printProgram(path, print, options) {
function printInverse(path, print, options) {
const node = path.getValue();
const inverse = path.call(print, "inverse");
const inverse = print("inverse");
const printed =
options.htmlWhitespaceSensitivity === "ignore"
? [hardline, inverse]
@@ -768,7 +768,7 @@ function printPathAndParams(path, print) {
}
function printPath(path, print) {
return path.call(print, "path");
return print("path");
}
function printParams(path, print) {
@@ -781,7 +781,7 @@ function printParams(path, print) {
}
if (node.hash && node.hash.pairs.length > 0) {
const hash = path.call(print, "hash");
const hash = print("hash");
parts.push(hash);
}
+4 -3
View File
@@ -1,6 +1,7 @@
"use strict";
const htmlVoidElements = require("html-void-elements");
const getLast = require("../utils/get-last");
function isLastNodeOfSiblings(path) {
const node = path.getValue();
@@ -8,14 +9,14 @@ function isLastNodeOfSiblings(path) {
if (
isParentOfSomeType(path, ["ElementNode"]) &&
parentNode.children[parentNode.children.length - 1] === node
getLast(parentNode.children) === node
) {
return true;
}
if (
isParentOfSomeType(path, ["Block"]) &&
parentNode.body[parentNode.body.length - 1] === node
getLast(parentNode.body) === node
) {
return true;
}
@@ -39,7 +40,7 @@ const voidTags = new Set(htmlVoidElements);
function isVoid(node) {
return (
(isGlimmerComponent(node) &&
node.children.every((n) => isWhitespaceNode(n))) ||
node.children.every((node) => isWhitespaceNode(node))) ||
voidTags.has(node.tag)
);
}
+2 -3
View File
@@ -2,6 +2,7 @@
const fromPairs = require("lodash/fromPairs");
const { isNonEmptyArray } = require("../common/util");
const getLast = require("../utils/get-last");
const NODES_KEYS = {
attrs: true,
children: true,
@@ -75,9 +76,7 @@ class Node {
}
get lastChild() {
return isNonEmptyArray(this.children)
? this.children[this.children.length - 1]
: null;
return isNonEmptyArray(this.children) ? getLast(this.children) : null;
}
// for element and attribute
+2 -1
View File
@@ -6,6 +6,7 @@ const {
ParseSourceFile,
} = require("angular-html-parser/lib/compiler/src/parse_util");
const parseFrontMatter = require("../utils/front-matter/parse");
const getLast = require("../utils/get-last");
const createError = require("../common/parser-create-error");
const { inferParserByLanguage } = require("../common/util");
const {
@@ -314,7 +315,7 @@ function _parse(text, options, parserOptions, shouldParseFrontMatter = true) {
);
subAst.sourceSpan = new ParseSourceSpan(
startSpan,
subAst.children[subAst.children.length - 1].sourceSpan.end
getLast(subAst.children).sourceSpan.end
);
const firstText = subAst.children[0];
if (firstText.length === offset) {
+2 -1
View File
@@ -3,6 +3,7 @@
const {
ParseSourceSpan,
} = require("angular-html-parser/lib/compiler/src/parse_util");
const getLast = require("../utils/get-last");
const {
htmlTrim,
getLeadingAndTrailingHtmlWhitespace,
@@ -141,7 +142,7 @@ function mergeNodeIntoText(ast, shouldMerge, getValue) {
if (
newChildren.length === 0 ||
newChildren[newChildren.length - 1].type !== "text"
getLast(newChildren).type !== "text"
) {
newChildren.push(newChild);
continue;
+3 -3
View File
@@ -322,7 +322,7 @@ function genericPrint(path, options, print) {
options.tabWidth *
countParents(
path,
(n) => n.parent && n.parent.type !== "root"
(node) => node.parent && node.parent.type !== "root"
)
}}$`
).test(node.lastChild.value)
@@ -546,7 +546,7 @@ function printChildren(path, options, print) {
];
}
return print(childPath);
return print();
}
function printBetweenLine(prevNode, nextNode) {
@@ -666,7 +666,7 @@ function printAttributes(path, options, print) {
options.originalText.slice(locStart(attribute), locEnd(attribute)),
literalline
)
: print(attributePath);
: print();
}, "attrs");
const forceNotToBreakAttrContent =
+2 -1
View File
@@ -1,6 +1,7 @@
"use strict";
const parseSrcset = require("parse-srcset");
const getLast = require("../utils/get-last");
const {
builders: { group, ifBreak, indent, join, line, softline },
} = require("../document");
@@ -89,7 +90,7 @@ function printClassNames(value) {
) {
groupedByPrefix.push([]);
}
groupedByPrefix[groupedByPrefix.length - 1].push(classNames[i]);
getLast(groupedByPrefix).push(classNames[i]);
previousPrefix = prefix;
}
+19 -5
View File
@@ -392,10 +392,7 @@ function handleClassComments({
isNonEmptyArray(enclosingNode.decorators) &&
!(followingNode && followingNode.type === "Decorator")
) {
addTrailingComment(
enclosingNode.decorators[enclosingNode.decorators.length - 1],
comment
);
addTrailingComment(getLast(enclosingNode.decorators), comment);
return true;
}
@@ -702,7 +699,13 @@ function handlePropertyComments({ comment, enclosingNode }) {
return false;
}
function handleOnlyComments({ comment, enclosingNode, ast, isLastComment }) {
function handleOnlyComments({
comment,
enclosingNode,
followingNode,
ast,
isLastComment,
}) {
// With Flow the enclosingNode is undefined so use the AST instead.
if (ast && ast.body && ast.body.length === 0) {
if (isLastComment) {
@@ -728,6 +731,17 @@ function handleOnlyComments({ comment, enclosingNode, ast, isLastComment }) {
return true;
}
if (
followingNode &&
followingNode.type === "Program" &&
followingNode.body.length === 0 &&
enclosingNode &&
enclosingNode.type === "ModuleExpression"
) {
addDanglingComment(followingNode, comment);
return true;
}
return false;
}
+13 -3
View File
@@ -1,5 +1,6 @@
"use strict";
const getLast = require("../utils/get-last");
const {
getFunctionParameters,
getLeftSidePathName,
@@ -354,6 +355,16 @@ function needsParens(path, options) {
) {
return true;
}
if (
name === "expression" &&
node.argument &&
node.argument.type === "PipelinePrimaryTopicReference" &&
parent.type === "PipelineTopicExpression"
) {
return true;
}
// else fallthrough
case "AwaitExpression":
switch (parent.type) {
@@ -383,6 +394,7 @@ function needsParens(path, options) {
if (!node.argument && parent.operator === "|>") {
return false;
}
return true;
}
@@ -862,9 +874,7 @@ function isFollowedByRightBracket(path) {
case "ObjectProperty":
if (name === "value") {
const parentParent = path.getParentNode(1);
return (
parentParent.properties[parentParent.properties.length - 1] === parent
);
return getLast(parentParent.properties) === parent;
}
break;
case "BinaryExpression":
-21
View File
@@ -3,21 +3,12 @@
const {
getLast,
getNextNonSpaceNonCommentCharacter,
getShebang,
} = require("../common/util");
const createError = require("../common/parser-create-error");
const { locStart, locEnd } = require("./loc");
const { isTypeCastComment } = require("./comments");
function postprocess(ast, options) {
if (
options.parser === "typescript" ||
options.parser === "flow" ||
options.parser === "espree"
) {
includeShebang(ast, options);
}
// Invalid decorators are removed since `@typescript-eslint/typescript-estree` v4
// https://github.com/typescript-eslint/typescript-eslint/pull/2375
if (options.parser === "typescript" && options.originalText.includes("@")) {
@@ -256,16 +247,4 @@ function rebalanceLogicalTree(node) {
});
}
function includeShebang(ast, options) {
const shebang = getShebang(options.originalText);
if (shebang) {
ast.comments.unshift({
type: "Line",
value: shebang.slice(2),
range: [0, shebang.length],
});
}
}
module.exports = postprocess;
+69 -22
View File
@@ -40,6 +40,7 @@ const parseOptions = {
"decimal",
"moduleStringNames",
"classStaticBlock",
"moduleBlocks",
],
tokens: true,
ranges: true,
@@ -144,31 +145,77 @@ const parseTypeScript = createParse(
);
const parseExpression = createParse("parseExpression", appendPlugins(["jsx"]));
const messagesShouldThrow = new Set([
// TSErrors.UnexpectedTypeAnnotation
// https://github.com/babel/babel/blob/008fe25ae22e78288fbc637d41069bb4a1040987/packages/babel-parser/src/plugins/typescript/index.js#L95
"Did not expect a type annotation here.",
// ErrorMessages.ModuleAttributeDifferentFromType
// https://github.com/babel/babel/blob/a023b6456cac4505096028f91c5b78829955bfc2/packages/babel-parser/src/parser/error-message.js#L92
"The only accepted module attribute is `type`",
// FlowErrors.UnexpectedTypeParameterBeforeAsyncArrowFunction
// https://github.com/babel/babel/blob/a023b6456cac4505096028f91c5b78829955bfc2/packages/babel-parser/src/plugins/flow.js#L118
"Type parameters must come after the async keyword, e.g. instead of `<T> async () => {}`, use `async <T>() => {}`",
// Rethrow on omitted call arguments: foo("a", , "b");
// ErrorMessages.UnexpectedToken
"Unexpected token ','",
// ErrorMessages.EscapedCharNotAnIdentifier
"Invalid Unicode escape",
// ErrorMessages.MissingUnicodeEscape
"Expecting Unicode escape sequence \\uXXXX",
// ErrorMessages.MissingSemicolon
"Missing semicolon",
]);
const allowedMessages = new Set([
"The only valid numeric escape in strict mode is '\\0'",
"'with' in strict mode",
"Legacy octal literals are not allowed in strict mode",
"Invalid left-hand side in parenthesized expression",
"Invalid left-hand side in assignment expression",
"Invalid left-hand side in postfix operation",
"Invalid left-hand side in prefix operation",
"Type argument list cannot be empty.",
"Type parameter list cannot be empty.",
"Type parameters cannot appear on a constructor declaration.",
"A parameter property may not be declared using a binding pattern.",
"A parameter property is only allowed in a constructor implementation.",
"Tuple members must all have names or all not have names.",
"Tuple members must be labeled with a simple identifier.",
"'abstract' modifier can only appear on a class, method, or property declaration.",
"'readonly' modifier can only appear on a property declaration or index signature.",
"Class methods cannot have the 'declare' modifier",
"Class methods cannot have the 'readonly' modifier",
"'public' modifier cannot appear on a type member.",
"'private' modifier cannot appear on a type member.",
"'protected' modifier cannot appear on a type member.",
"'static' modifier cannot appear on a type member.",
"'declare' modifier cannot appear on a type member.",
"'abstract' modifier cannot appear on a type member.",
"'readonly' modifier cannot appear on a type member.",
"Accessibility modifier already seen.",
"Index signatures cannot have the 'declare' modifier",
"Using the export keyword between a decorator and a class is not allowed. Please use `export @dec class` instead.",
"Argument name clash",
"Invalid decimal",
"Unexpected trailing comma after rest element",
"Decorators cannot be used to decorate parameters",
"Unterminated JSX contents",
"Invalid parenthesized assignment pattern",
'Unexpected token, expected "}"',
"Unexpected token :",
"Unexpected reserved word 'package'",
'Duplicate key "type" is not allowed in module attributes',
"No line break is allowed before '=>'",
"Invalid escape sequence in template",
"Abstract methods can only appear within an abstract class.",
"Decorators cannot be used to decorate object literal properties",
"A required element cannot follow an optional element.",
"A binding pattern parameter cannot be optional in an implementation signature.",
"Initializers are not allowed in ambient contexts.",
"A type-only import can specify a default import or named bindings, but not both.",
"An implementation cannot be declared in ambient contexts.",
"Classes may not have a field named 'constructor'",
]);
function shouldRethrowRecoveredError(error) {
const [, message] = error.message.match(/(.*?)\s*\(\d+:\d+\)/);
// Only works for literal message
return messagesShouldThrow.has(message);
if (
allowedMessages.has(message) ||
/^Identifier '.*?' has already been declared$/.test(message) ||
/^Private name #.*? is not defined$/.test(message) ||
/^`.*?` has already been exported\. Exported identifiers must be unique\.$/.test(
message
)
) {
return false;
}
return true;
}
const babel = createParser(parse);
+4 -9
View File
@@ -1,9 +1,9 @@
"use strict";
const { getShebang } = require("../common/util");
const createError = require("../common/parser-create-error");
const tryCombinations = require("../utils/try-combinations");
const postprocess = require("./parse-postprocess");
const createParser = require("./parser/create-parser");
const replaceHashbang = require("./parser/replace-hashbang");
const parseOptions = {
range: true,
@@ -33,15 +33,10 @@ function parse(originalText, parsers, options) {
const { parse, latestEcmaVersion } = require("espree");
parseOptions.ecmaVersion = latestEcmaVersion;
// Replace shebang with space
const shebang = getShebang(originalText);
const text = shebang
? " ".repeat(shebang.length) + originalText.slice(shebang.length)
: originalText;
const textToParse = replaceHashbang(originalText);
const { result: ast, error: moduleParseError } = tryCombinations(
() => parse(text, { ...parseOptions, sourceType: "module" }),
() => parse(text, { ...parseOptions, sourceType: "script" })
() => parse(textToParse, { ...parseOptions, sourceType: "module" }),
() => parse(textToParse, { ...parseOptions, sourceType: "script" })
);
if (!ast) {
+2 -1
View File
@@ -3,6 +3,7 @@
const createError = require("../common/parser-create-error");
const postprocess = require("./parse-postprocess");
const createParser = require("./parser/create-parser");
const replaceHashbang = require("./parser/replace-hashbang");
// https://github.com/facebook/flow/tree/master/packages/flow-parser#options
const parseOptions = {
@@ -47,7 +48,7 @@ function createParseError(error) {
function parse(text, parsers, opts) {
// Inline the require to avoid loading all the JS if we don't use it
const { parse } = require("flow-parser");
const ast = parse(text, parseOptions);
const ast = parse(replaceHashbang(text), parseOptions);
const [error] = ast.errors;
if (error) {
throw createParseError(error);
+4 -2
View File
@@ -4,6 +4,7 @@ const createError = require("../common/parser-create-error");
const tryCombinations = require("../utils/try-combinations");
const postprocess = require("./parse-postprocess");
const createParser = require("./parser/create-parser");
const replaceHashbang = require("./parser/replace-hashbang");
/** @type {import("@typescript-eslint/typescript-estree").TSESTreeOptions} */
const parseOptions = {
@@ -33,14 +34,15 @@ function createParseError(error) {
}
function parse(text, parsers, opts) {
const textToParse = replaceHashbang(text);
const jsx = isProbablyJsx(text);
const { parseWithNodeMaps } = require("@typescript-eslint/typescript-estree");
const { result, error: firstError } = tryCombinations(
// Try passing with our best guess first.
() => parseWithNodeMaps(text, { ...parseOptions, jsx }),
() => parseWithNodeMaps(textToParse, { ...parseOptions, jsx }),
// But if we get it wrong, try the opposite.
() => parseWithNodeMaps(text, { ...parseOptions, jsx: !jsx })
() => parseWithNodeMaps(textToParse, { ...parseOptions, jsx: !jsx })
);
if (!result) {
+15 -4
View File
@@ -73,14 +73,25 @@ function assertJsonNode(node) {
assertJsonNode(node.value);
return;
case "UnaryExpression":
if (node.operator !== "+" && node.operator !== "-") {
case "UnaryExpression": {
const { operator, argument } = node;
if (operator !== "+" && operator !== "-") {
throw createJsonError(node, `Operator '${node.operator}'`);
}
assertJsonNode(node.argument);
if (
argument.type === "NumericLiteral" ||
(argument.type === "Identifier" &&
(argument.name === "Infinity" || argument.name === "NaN"))
) {
return;
}
return;
throw createJsonError(
argument,
`Operator '${operator}' before '${argument.type}'`
);
}
case "Identifier":
if (
// JSON5 https://spec.json5.org/#numbers
@@ -0,0 +1,13 @@
"use strict";
// Replace `#!` with `//` so `typescript`, `flow`, and `espree` can parse it as line comment
// Inspired by ESLint parse function https://github.com/eslint/eslint/blob/9d6063add931f0803cae1676d5df307baf114360/lib/linter/linter.js#L635
function replaceHashbang(text) {
if (text.charAt(0) === "#" && text.charAt(1) === "!") {
return "//" + text.slice(2);
}
return text;
}
module.exports = replaceHashbang;
+23 -24
View File
@@ -9,14 +9,14 @@ const { printBinaryishExpression } = require("./binaryish");
/** @typedef {import("../../common/ast-path")} AstPath */
function printAngular(path, options, print) {
const n = path.getValue();
switch (n.type) {
const node = path.getValue();
switch (node.type) {
case "NGRoot":
return [
path.call(print, "node"),
!hasComment(n.node)
print("node"),
!hasComment(node.node)
? ""
: " //" + getComments(n.node)[0].value.trimEnd(),
: " //" + getComments(node.node)[0].value.trimEnd(),
];
case "NGPipeExpression":
return printBinaryishExpression(path, options, print);
@@ -26,9 +26,7 @@ function printAngular(path, options, print) {
[";", line],
path.map(
(childPath) =>
hasNgSideEffect(childPath)
? print(childPath)
: ["(", print(childPath), ")"],
hasNgSideEffect(childPath) ? print() : ["(", print(), ")"],
"expressions"
)
)
@@ -36,54 +34,55 @@ function printAngular(path, options, print) {
case "NGEmptyExpression":
return "";
case "NGQuotedExpression":
return [n.prefix, ": ", n.value.trim()];
return [node.prefix, ": ", node.value.trim()];
case "NGMicrosyntax":
return path.map(
(childPath, index) => [
index === 0
? ""
: isNgForOf(childPath.getValue(), index, n)
: isNgForOf(childPath.getValue(), index, node)
? " "
: [";", line],
print(childPath),
print(),
],
"body"
);
case "NGMicrosyntaxKey":
return /^[$_a-z][\w$]*(-[$_a-z][\w$])*$/i.test(n.name)
? n.name
: JSON.stringify(n.name);
return /^[$_a-z][\w$]*(-[$_a-z][\w$])*$/i.test(node.name)
? node.name
: JSON.stringify(node.name);
case "NGMicrosyntaxExpression":
return [
path.call(print, "expression"),
n.alias === null ? "" : [" as ", path.call(print, "alias")],
print("expression"),
node.alias === null ? "" : [" as ", print("alias")],
];
case "NGMicrosyntaxKeyedExpression": {
const index = path.getName();
const parentNode = path.getParentNode();
const shouldNotPrintColon =
isNgForOf(n, index, parentNode) ||
(((index === 1 && (n.key.name === "then" || n.key.name === "else")) ||
isNgForOf(node, index, parentNode) ||
(((index === 1 &&
(node.key.name === "then" || node.key.name === "else")) ||
(index === 2 &&
n.key.name === "else" &&
node.key.name === "else" &&
parentNode.body[index - 1].type ===
"NGMicrosyntaxKeyedExpression" &&
parentNode.body[index - 1].key.name === "then")) &&
parentNode.body[0].type === "NGMicrosyntaxExpression");
return [
path.call(print, "key"),
print("key"),
shouldNotPrintColon ? " " : ": ",
path.call(print, "expression"),
print("expression"),
];
}
case "NGMicrosyntaxLet":
return [
"let ",
path.call(print, "key"),
n.value === null ? "" : [" = ", path.call(print, "value")],
print("key"),
node.value === null ? "" : [" = ", print("value")],
];
case "NGMicrosyntaxAs":
return [path.call(print, "key"), " as ", path.call(print, "alias")];
return [print("key"), " as ", print("alias")];
}
}
+31 -27
View File
@@ -20,14 +20,14 @@ const { printOptionalToken, printTypeAnnotation } = require("./misc");
/** @typedef {import("../../document").Doc} Doc */
function printArray(path, options, print) {
const n = path.getValue();
const node = path.getValue();
/** @type{Doc[]} */
const parts = [];
const openBracket = n.type === "TupleExpression" ? "#[" : "[";
const openBracket = node.type === "TupleExpression" ? "#[" : "[";
const closeBracket = "]";
if (n.elements.length === 0) {
if (!hasComment(n, CommentCheckFlags.Dangling)) {
if (node.elements.length === 0) {
if (!hasComment(node, CommentCheckFlags.Dangling)) {
parts.push(openBracket, closeBracket);
} else {
parts.push(
@@ -40,7 +40,7 @@ function printArray(path, options, print) {
);
}
} else {
const lastElem = getLast(n.elements);
const lastElem = getLast(node.elements);
const canHaveTrailingComma = !(lastElem && lastElem.type === "RestElement");
// JavaScript allows you to have empty elements in an array which
@@ -59,8 +59,8 @@ function printArray(path, options, print) {
const shouldBreak =
!options.__inJestEach &&
n.elements.length > 1 &&
n.elements.every((element, i, elements) => {
node.elements.length > 1 &&
node.elements.every((element, i, elements) => {
const elementType = element && element.type;
if (
elementType !== "ArrayExpression" &&
@@ -80,23 +80,7 @@ function printArray(path, options, print) {
return element[itemsKey] && element[itemsKey].length > 1;
});
const shouldUseConciseFormatting =
n.elements.length > 1 &&
n.elements.every(
(element) =>
element &&
(isNumericLiteral(element) ||
(isSignedNumericLiteral(element) &&
!hasComment(element.argument))) &&
!hasComment(
element,
CommentCheckFlags.Trailing | CommentCheckFlags.Line,
(comment) =>
!hasNewline(options.originalText, locStart(comment), {
backwards: true,
})
)
);
const shouldUseConciseFormatting = isConciselyPrintedArray(node, options);
const trailingComma = !canHaveTrailingComma
? ""
@@ -138,12 +122,32 @@ function printArray(path, options, print) {
return parts;
}
function isConciselyPrintedArray(node, options) {
return (
node.elements.length > 1 &&
node.elements.every(
(element) =>
element &&
(isNumericLiteral(element) ||
(isSignedNumericLiteral(element) && !hasComment(element.argument))) &&
!hasComment(
element,
CommentCheckFlags.Trailing | CommentCheckFlags.Line,
(comment) =>
!hasNewline(options.originalText, locStart(comment), {
backwards: true,
})
)
)
);
}
function printArrayItems(path, options, printPath, print) {
const printedElements = [];
let separatorParts = [];
path.each((childPath) => {
printedElements.push(separatorParts, group(print(childPath)));
printedElements.push(separatorParts, group(print()));
separatorParts = [",", line];
if (
@@ -163,7 +167,7 @@ function printArrayItemsConcisely(path, options, print, trailingComma) {
path.each((childPath, i, elements) => {
const isLast = i === elements.length - 1;
parts.push([print(childPath), isLast ? trailingComma : ","]);
parts.push([print(), isLast ? trailingComma : ","]);
if (!isLast) {
parts.push(
@@ -182,4 +186,4 @@ function printArrayItemsConcisely(path, options, print, trailingComma) {
return fill(parts);
}
module.exports = { printArray, printArrayItems };
module.exports = { printArray, printArrayItems, isConciselyPrintedArray };
+5 -15
View File
@@ -27,10 +27,7 @@ function printAssignment(
) {
const layout = chooseLayout(path, options, leftDoc, rightPropertyName);
const rightDoc = path.call(
(p) => print(p, { assignmentLayout: layout }),
rightPropertyName
);
const rightDoc = print(rightPropertyName, { assignmentLayout: layout });
switch (layout) {
// First break after operator, then the sides are broken independently on their own lines
@@ -69,26 +66,19 @@ function printAssignment(
}
function printAssignmentExpression(path, options, print) {
const n = path.getValue();
const node = path.getValue();
return printAssignment(
path,
options,
print,
path.call(print, "left"),
[" ", n.operator],
print("left"),
[" ", node.operator],
"right"
);
}
function printVariableDeclarator(path, options, print) {
return printAssignment(
path,
options,
print,
path.call(print, "id"),
" =",
"init"
);
return printAssignment(path, options, print, print("id"), " =", "init");
}
function chooseLayout(path, options, leftDoc, rightPropertyName) {
+15 -15
View File
@@ -30,11 +30,11 @@ const {
let uid = 0;
function printBinaryishExpression(path, options, print) {
const n = path.getValue();
const node = path.getValue();
const parent = path.getParentNode();
const parentParent = path.getParentNode(1);
const isInsideParenthesis =
n !== parent.body &&
node !== parent.body &&
(parent.type === "IfStatement" ||
parent.type === "WhileStatement" ||
parent.type === "SwitchStatement" ||
@@ -71,7 +71,7 @@ function printBinaryishExpression(path, options, print) {
// c
// ).call()
if (
(isCallExpression(parent) && parent.callee === n) ||
(isCallExpression(parent) && parent.callee === node) ||
parent.type === "UnaryExpression" ||
(isMemberExpression(parent) && !parent.computed)
) {
@@ -85,14 +85,14 @@ function printBinaryishExpression(path, options, print) {
parent.type === "ThrowStatement" ||
(parent.type === "JSXExpressionContainer" &&
parentParent.type === "JSXAttribute") ||
(n.operator !== "|" && parent.type === "JsExpressionRoot") ||
(n.type !== "NGPipeExpression" &&
(node.operator !== "|" && parent.type === "JsExpressionRoot") ||
(node.type !== "NGPipeExpression" &&
((parent.type === "NGRoot" && options.parser === "__ng_binding") ||
(parent.type === "NGMicrosyntaxExpression" &&
parentParent.type === "NGMicrosyntax" &&
parentParent.body.length === 1))) ||
(n === parent.body && parent.type === "ArrowFunctionExpression") ||
(n !== parent.body && parent.type === "ForStatement") ||
(node === parent.body && parent.type === "ArrowFunctionExpression") ||
(node !== parent.body && parent.type === "ForStatement") ||
(parent.type === "ConditionalExpression" &&
parentParent.type !== "ReturnStatement" &&
parentParent.type !== "ThrowStatement" &&
@@ -110,12 +110,12 @@ function printBinaryishExpression(path, options, print) {
parent.type === "Property";
const samePrecedenceSubExpression =
isBinaryish(n.left) && shouldFlatten(n.operator, n.left.operator);
isBinaryish(node.left) && shouldFlatten(node.operator, node.left.operator);
if (
shouldNotIndent ||
(shouldInlineLogicalExpression(n) && !samePrecedenceSubExpression) ||
(!shouldInlineLogicalExpression(n) && shouldIndentIfInlining)
(shouldInlineLogicalExpression(node) && !samePrecedenceSubExpression) ||
(!shouldInlineLogicalExpression(node) && shouldIndentIfInlining)
) {
return group(parts);
}
@@ -133,7 +133,7 @@ function printBinaryishExpression(path, options, print) {
// </Foo>
// )
const hasJsx = isJsxNode(n.right);
const hasJsx = isJsxNode(node.right);
const firstGroupIndex = parts.findIndex(
(part) =>
@@ -217,7 +217,7 @@ function printBinaryishExpressions(
),
];
} else {
parts.push(group(path.call(print, "left")));
parts.push(group(print("left")));
}
const shouldInline = shouldInlineLogicalExpression(node);
@@ -243,12 +243,12 @@ function printBinaryishExpressions(
: "";
const right = shouldInline
? [operator, " ", path.call(print, "right"), rightSuffix]
? [operator, " ", print("right"), rightSuffix]
: [
lineBeforeOperator ? line : "",
operator,
lineBeforeOperator ? " " : line,
path.call(print, "right"),
print("right"),
rightSuffix,
];
@@ -285,7 +285,7 @@ function printBinaryishExpressions(
}
} else {
// Our stopping case. Simply print the node normally.
parts.push(group(path.call(print)));
parts.push(group(print()));
}
return parts;
+5 -2
View File
@@ -75,7 +75,7 @@ function printBlockBody(path, options, print) {
// Babel 6
if (nodeHasDirectives) {
path.each((childPath, index, directives) => {
parts.push(print(childPath));
parts.push(print());
if (index < directives.length - 1 || nodeHasBody || nodeHasComment) {
parts.push(hardline);
if (isNextLineEmpty(childPath.getValue(), options)) {
@@ -94,7 +94,10 @@ function printBlockBody(path, options, print) {
}
if (node.type === "Program") {
parts.push(hardline);
const parent = path.getParentNode();
if (!parent || parent.type !== "ModuleExpression") {
parts.push(hardline);
}
}
return parts;
+17 -16
View File
@@ -31,6 +31,8 @@ const {
utils: { willBreak },
} = require("../../document");
const { isConciselyPrintedArray } = require("./array");
function printCallArguments(path, options, print) {
const node = path.getValue();
const isDynamicImport = node.type === "ImportExpression";
@@ -46,13 +48,7 @@ function printCallArguments(path, options, print) {
// useEffect(() => { ... }, [foo, bar, baz])
if (isReactHookCallWithDepsArray(args)) {
return [
"(",
path.call(print, "arguments", 0),
", ",
path.call(print, "arguments", 1),
")",
];
return ["(", print(["arguments", 0]), ", ", print(["arguments", 1]), ")"];
}
// func(
@@ -74,8 +70,8 @@ function printCallArguments(path, options, print) {
}
let shouldBreak = false;
iterateFunctionParametersPath(argPath, (parameterPath) => {
shouldBreak = shouldBreak || willBreak(print(parameterPath));
iterateFunctionParametersPath(argPath, () => {
shouldBreak = shouldBreak || willBreak(print());
});
return shouldBreak;
@@ -88,7 +84,7 @@ function printCallArguments(path, options, print) {
const printedArguments = [];
iterateCallArgumentsPath(path, (argPath, index) => {
const arg = argPath.getNode();
const parts = [print(argPath)];
const parts = [print()];
if (index === lastArgIndex) {
// do nothing
@@ -133,7 +129,7 @@ function printCallArguments(path, options, print) {
}
const shouldGroupFirst = shouldGroupFirstArg(args);
const shouldGroupLast = shouldGroupLastArg(args);
const shouldGroupLast = shouldGroupLastArg(args, options);
if (shouldGroupFirst || shouldGroupLast) {
const shouldBreak =
(shouldGroupFirst
@@ -148,7 +144,7 @@ function printCallArguments(path, options, print) {
if (shouldGroupFirst && i === 0) {
printedExpanded = [
[
argPath.call((p) => print(p, { expandFirstArg: true })),
print([], { expandFirstArg: true }),
printedArguments.length > 1 ? "," : "",
hasEmptyLineFollowingFirstArg ? hardline : line,
hasEmptyLineFollowingFirstArg ? hardline : "",
@@ -159,7 +155,7 @@ function printCallArguments(path, options, print) {
if (shouldGroupLast && i === args.length - 1) {
printedExpanded = [
...printedArguments.slice(0, -1),
argPath.call((p) => print(p, { expandLastArg: true })),
print([], { expandLastArg: true }),
];
}
});
@@ -255,7 +251,7 @@ function couldGroupArg(arg, arrowChainRecursion = false) {
);
}
function shouldGroupLastArg(args) {
function shouldGroupLastArg(args, options) {
const lastArg = getLast(args);
const penultimateArg = getPenultimate(args);
return (
@@ -267,8 +263,13 @@ function shouldGroupLastArg(args) {
(!penultimateArg || penultimateArg.type !== lastArg.type) &&
// useMemo(() => func(), [foo, bar, baz])
(args.length !== 2 ||
args[0].type !== "ArrowFunctionExpression" ||
args[1].type !== "ArrayExpression")
penultimateArg.type !== "ArrowFunctionExpression" ||
lastArg.type !== "ArrayExpression") &&
!(
args.length > 1 &&
lastArg.type === "ArrayExpression" &&
isConciselyPrintedArray(lastArg, options)
)
);
}
+45 -22
View File
@@ -9,6 +9,7 @@ const {
hasFlowAnnotationComment,
isCallExpression,
isMemberish,
isStringLiteral,
isTemplateOnItsOwnLine,
isTestCall,
iterateCallArgumentsPath,
@@ -18,36 +19,34 @@ const printCallArguments = require("./call-arguments");
const { printOptionalToken, printFunctionTypeParameters } = require("./misc");
function printCallExpression(path, options, print) {
const n = path.getValue();
const isNew = n.type === "NewExpression";
const isDynamicImport = n.type === "ImportExpression";
const node = path.getValue();
const parentNode = path.getParentNode();
const isNew = node.type === "NewExpression";
const isDynamicImport = node.type === "ImportExpression";
const optional = printOptionalToken(path);
const args = getCallArguments(n);
const args = getCallArguments(node);
if (
// Dangling comments not handled, all these special cases should has argument #9668
// Dangling comments are not handled, all these special cases should have arguments #9668
args.length > 0 &&
// We want to keep CommonJS- and AMD-style require calls, and AMD-style
// define calls, as a unit.
// e.g. `define(["some/lib", (lib) => {`
((!isDynamicImport &&
!isNew &&
n.callee.type === "Identifier" &&
(n.callee.name === "require" || n.callee.name === "define")) ||
// e.g. `define(["some/lib"], (lib) => {`
((!isDynamicImport && !isNew && isCommonsJsOrAmdCall(node, parentNode)) ||
// Template literals as single arguments
(args.length === 1 &&
isTemplateOnItsOwnLine(args[0], options.originalText)) ||
// Keep test declarations on a single line
// e.g. `it('long name', () => {`
(!isNew && isTestCall(n, path.getParentNode())))
(!isNew && isTestCall(node, parentNode)))
) {
const printed = [];
iterateCallArgumentsPath(path, (argPath) => {
printed.push(print(argPath));
iterateCallArgumentsPath(path, () => {
printed.push(print());
});
return [
isNew ? "new " : "",
path.call(print, "callee"),
print("callee"),
optional,
printFunctionTypeParameters(path, options, print),
"(",
@@ -64,11 +63,11 @@ function printCallExpression(path, options, print) {
// Here, we ensure that such comments stay between the Identifier and the Callee.
const isIdentifierWithFlowAnnotation =
(options.parser === "babel" || options.parser === "babel-flow") &&
n.callee &&
n.callee.type === "Identifier" &&
hasFlowAnnotationComment(n.callee.trailingComments);
node.callee &&
node.callee.type === "Identifier" &&
hasFlowAnnotationComment(node.callee.trailingComments);
if (isIdentifierWithFlowAnnotation) {
n.callee.trailingComments[0].printed = true;
node.callee.trailingComments[0].printed = true;
}
// We detect calls on member lookups and possibly print them in a
@@ -76,7 +75,7 @@ function printCallExpression(path, options, print) {
if (
!isDynamicImport &&
!isNew &&
isMemberish(n.callee) &&
isMemberish(node.callee) &&
!path.call((path) => pathNeedsParens(path, options), "callee")
) {
return printMemberChain(path, options, print);
@@ -84,10 +83,10 @@ function printCallExpression(path, options, print) {
const contents = [
isNew ? "new " : "",
isDynamicImport ? "import" : path.call(print, "callee"),
isDynamicImport ? "import" : print("callee"),
optional,
isIdentifierWithFlowAnnotation
? `/*:: ${n.callee.trailingComments[0].value.slice(2).trim()} */`
? `/*:: ${node.callee.trailingComments[0].value.slice(2).trim()} */`
: "",
printFunctionTypeParameters(path, options, print),
printCallArguments(path, options, print),
@@ -95,11 +94,35 @@ function printCallExpression(path, options, print) {
// We group here when the callee is itself a call expression.
// See `isLongCurriedCallExpression` for more info.
if (isDynamicImport || isCallExpression(n.callee)) {
if (isDynamicImport || isCallExpression(node.callee)) {
return group(contents);
}
return contents;
}
function isCommonsJsOrAmdCall(node, parentNode) {
if (node.callee.type !== "Identifier") {
return false;
}
if (node.callee.name === "require") {
return true;
}
if (node.callee.name === "define") {
const args = getCallArguments(node);
return (
parentNode.type === "ExpressionStatement" &&
(args.length === 1 ||
(args.length === 2 && args[0].type === "ArrayExpression") ||
(args.length === 3 &&
isStringLiteral(args[0]) &&
args[1].type === "ArrayExpression"))
);
}
return false;
}
module.exports = { printCallExpression };
+39 -39
View File
@@ -14,14 +14,14 @@ const { printAssignment } = require("./assignment");
const { printClassMemberDecorators } = require("./decorators");
function printClass(path, options, print) {
const n = path.getValue();
const node = path.getValue();
const parts = [];
if (n.declare) {
if (node.declare) {
parts.push("declare ");
}
if (n.abstract) {
if (node.abstract) {
parts.push("abstract ");
}
@@ -30,26 +30,26 @@ function printClass(path, options, print) {
// Keep old behaviour of extends in same line
// If there is only on extends and there are not comments
const groupMode =
(n.id && hasComment(n.id, CommentCheckFlags.Trailing)) ||
(n.superClass && hasComment(n.superClass)) ||
isNonEmptyArray(n.extends) || // DeclareClass
isNonEmptyArray(n.mixins) ||
isNonEmptyArray(n.implements);
(node.id && hasComment(node.id, CommentCheckFlags.Trailing)) ||
(node.superClass && hasComment(node.superClass)) ||
isNonEmptyArray(node.extends) || // DeclareClass
isNonEmptyArray(node.mixins) ||
isNonEmptyArray(node.implements);
const partsGroup = [];
const extendsParts = [];
if (n.id) {
partsGroup.push(" ", path.call(print, "id"));
if (node.id) {
partsGroup.push(" ", print("id"));
}
partsGroup.push(path.call(print, "typeParameters"));
partsGroup.push(print("typeParameters"));
if (n.superClass) {
if (node.superClass) {
const printed = [
"extends ",
printSuperClass(path, options, print),
path.call(print, "superTypeParameters"),
print("superTypeParameters"),
];
const printedWithComments = path.call(
(superClass) => printComments(superClass, printed, options),
@@ -71,17 +71,17 @@ function printClass(path, options, print) {
if (groupMode) {
let printedPartsGroup;
if (shouldIndentOnlyHeritageClauses(n)) {
if (shouldIndentOnlyHeritageClauses(node)) {
printedPartsGroup = [...partsGroup, indent(extendsParts)];
} else {
printedPartsGroup = indent([...partsGroup, extendsParts]);
}
parts.push(group(printedPartsGroup, { id: getHeritageGroupId(n) }));
parts.push(group(printedPartsGroup, { id: getHeritageGroupId(node) }));
} else {
parts.push(...partsGroup, ...extendsParts);
}
parts.push(" ", path.call(print, "body"));
parts.push(" ", print("body"));
return parts;
}
@@ -112,8 +112,8 @@ function shouldIndentOnlyHeritageClauses(node) {
}
function printList(path, options, print, listName) {
const n = path.getValue();
if (!isNonEmptyArray(n[listName])) {
const node = path.getValue();
if (!isNonEmptyArray(node[listName])) {
return "";
}
@@ -124,9 +124,9 @@ function printList(path, options, print, listName) {
({ marker }) => marker === listName
);
return [
shouldIndentOnlyHeritageClauses(n)
shouldIndentOnlyHeritageClauses(node)
? ifBreak(" ", line, {
groupId: getTypeParametersGroupId(n.typeParameters),
groupId: getTypeParametersGroupId(node.typeParameters),
})
: line,
printedLeadingComments,
@@ -137,7 +137,7 @@ function printList(path, options, print, listName) {
}
function printSuperClass(path, options, print) {
const printed = path.call(print, "superClass");
const printed = print("superClass");
const parent = path.getParentNode();
if (parent.type === "AssignmentExpression") {
return group(
@@ -148,28 +148,28 @@ function printSuperClass(path, options, print) {
}
function printClassMethod(path, options, print) {
const n = path.getValue();
const node = path.getValue();
const parts = [];
if (isNonEmptyArray(n.decorators)) {
if (isNonEmptyArray(node.decorators)) {
parts.push(printClassMemberDecorators(path, options, print));
}
if (n.accessibility) {
parts.push(n.accessibility + " ");
if (node.accessibility) {
parts.push(node.accessibility + " ");
}
// "readonly" and "declare" are supported by only "babel-ts"
// https://github.com/prettier/prettier/issues/9760
if (n.readonly) {
if (node.readonly) {
parts.push("readonly ");
}
if (n.declare) {
if (node.declare) {
parts.push("declare ");
}
if (n.static) {
if (node.static) {
parts.push("static ");
}
if (n.type === "TSAbstractMethodDefinition" || n.abstract) {
if (node.type === "TSAbstractMethodDefinition" || node.abstract) {
parts.push("abstract ");
}
@@ -179,30 +179,30 @@ function printClassMethod(path, options, print) {
}
function printClassProperty(path, options, print) {
const n = path.getValue();
const node = path.getValue();
const parts = [];
const semi = options.semi ? ";" : "";
if (isNonEmptyArray(n.decorators)) {
if (isNonEmptyArray(node.decorators)) {
parts.push(printClassMemberDecorators(path, options, print));
}
if (n.accessibility) {
parts.push(n.accessibility + " ");
if (node.accessibility) {
parts.push(node.accessibility + " ");
}
if (n.declare) {
if (node.declare) {
parts.push("declare ");
}
if (n.static) {
if (node.static) {
parts.push("static ");
}
if (n.type === "TSAbstractClassProperty" || n.abstract) {
if (node.type === "TSAbstractClassProperty" || node.abstract) {
parts.push("abstract ");
}
if (n.readonly) {
if (node.readonly) {
parts.push("readonly ");
}
if (n.variance) {
parts.push(path.call(print, "variance"));
if (node.variance) {
parts.push(print("variance"));
}
parts.push(
printPropertyKey(path, options, print),
+14 -11
View File
@@ -10,6 +10,7 @@ const {
printUnionType,
printFunctionType,
printTupleType,
printIndexedAccessType,
} = require("./type-annotation");
const { printInterface } = require("./interface");
const { printTypeParameters } = require("./type-parameters");
@@ -19,35 +20,35 @@ const {
} = require("./module");
function printFlow(path, options, print) {
const n = path.getValue();
const node = path.getValue();
const semi = options.semi ? ";" : "";
switch (n.type) {
switch (node.type) {
case "DeclareClass":
return printFlowDeclaration(path, printClass(path, options, print));
case "DeclareFunction":
return printFlowDeclaration(path, [
"function ",
path.call(print, "id"),
n.predicate ? " " : "",
path.call(print, "predicate"),
print("id"),
node.predicate ? " " : "",
print("predicate"),
semi,
]);
case "DeclareModule":
return printFlowDeclaration(path, [
"module ",
path.call(print, "id"),
print("id"),
" ",
path.call(print, "body"),
print("body"),
]);
case "DeclareModuleExports":
return printFlowDeclaration(path, [
"module.exports",
": ",
path.call(print, "typeAnnotation"),
print("typeAnnotation"),
semi,
]);
case "DeclareVariable":
return printFlowDeclaration(path, ["var ", path.call(print, "id"), semi]);
return printFlowDeclaration(path, ["var ", print("id"), semi]);
case "DeclareOpaqueType":
return printFlowDeclaration(path, printOpaqueType(path, options, print));
case "DeclareInterface":
@@ -78,13 +79,15 @@ function printFlow(path, options, print) {
return printTupleType(path, options, print);
case "GenericTypeAnnotation":
return [
path.call(print, "id"),
print("id"),
printTypeParameters(path, options, print, "typeParameters"),
];
case "IndexedAccessType":
return printIndexedAccessType(path, options, print);
// Type Annotations for Facebook Flow, typically stripped out or
// transformed away before printing.
case "TypeAnnotation":
return path.call(print, "typeAnnotation");
return print("typeAnnotation");
}
}
+1 -1
View File
@@ -65,7 +65,7 @@ function printFunctionParameters(
if (isLastParameter && functionNode.rest) {
printed.push("...");
}
printed.push(parameterPath.call(print));
printed.push(print());
if (isLastParameter) {
return;
}
+74 -58
View File
@@ -1,8 +1,14 @@
"use strict";
/** @typedef {import("../../document/doc-builders").Doc} Doc */
/** @type {import("assert")} */
const assert = require("assert");
const { printDanglingComments, printComments } = require("../../main/comments");
const {
printDanglingComments,
printCommentsSeparately,
} = require("../../main/comments");
const getLast = require("../../utils/get-last");
const {
getNextNonSpaceNonCommentCharacterIndex,
} = require("../../common/util");
@@ -43,27 +49,27 @@ const { printPropertyKey } = require("./property");
const { printFunctionTypeParameters } = require("./misc");
function printFunctionDeclaration(path, print, options, expandArg) {
const n = path.getValue();
const node = path.getValue();
const parts = [];
// For TypeScript the TSDeclareFunction node shares the AST
// structure with FunctionDeclaration
if (n.type === "TSDeclareFunction" && n.declare) {
if (node.type === "TSDeclareFunction" && node.declare) {
parts.push("declare ");
}
if (n.async) {
if (node.async) {
parts.push("async ");
}
if (n.generator) {
if (node.generator) {
parts.push("function* ");
} else {
parts.push("function ");
}
if (n.id) {
parts.push(path.call(print, "id"));
if (node.id) {
parts.push(print("id"));
}
const parametersDoc = printFunctionParameters(
@@ -73,7 +79,10 @@ function printFunctionDeclaration(path, print, options, expandArg) {
expandArg
);
const returnTypeDoc = printReturnType(path, print, options);
const shouldGroupParameters = shouldGroupFunctionParameters(n, returnTypeDoc);
const shouldGroupParameters = shouldGroupFunctionParameters(
node,
returnTypeDoc
);
parts.push(
printFunctionTypeParameters(path, options, print),
@@ -81,11 +90,11 @@ function printFunctionDeclaration(path, print, options, expandArg) {
shouldGroupParameters ? group(parametersDoc) : parametersDoc,
returnTypeDoc,
]),
n.body ? " " : "",
path.call(print, "body")
node.body ? " " : "",
print("body")
);
if (options.semi && (n.declare || !n.body)) {
if (options.semi && (node.declare || !node.body)) {
parts.push(";");
}
@@ -125,7 +134,7 @@ function printMethod(path, options, print) {
path.call((path) => printMethodInternal(path, options, print), "value")
);
} else {
parts.push(path.call(print, "value"));
parts.push(print("value"));
}
return parts;
@@ -148,7 +157,7 @@ function printMethodInternal(path, options, print) {
];
if (node.body) {
parts.push(" ", path.call(print, "body"));
parts.push(" ", print("body"));
} else {
parts.push(options.semi ? ";" : "");
}
@@ -157,15 +166,15 @@ function printMethodInternal(path, options, print) {
}
function printArrowFunctionSignature(path, options, print, args) {
const n = path.getValue();
const node = path.getValue();
const parts = [];
if (n.async) {
if (node.async) {
parts.push("async ");
}
if (shouldPrintParamsWithoutParens(path, options)) {
parts.push(path.call(print, "params", 0));
parts.push(print(["params", 0]));
} else {
parts.push(
group([
@@ -242,37 +251,49 @@ function printArrowChain(
}
function printArrowFunctionExpression(path, options, print, args) {
let n = path.getValue();
let node = path.getValue();
/** @type {Doc[]} */
const signatures = [];
let body;
const body = [];
let chainShouldBreak = false;
path.call(function rec(path) {
(function rec() {
const doc = printArrowFunctionSignature(path, options, print, args);
signatures.push(
signatures.length === 0 ? doc : printComments(path, doc, options)
);
if (signatures.length === 0) {
signatures.push(doc);
} else {
const { leading, trailing } = printCommentsSeparately(path, options);
signatures.push([leading, doc]);
body.unshift(trailing);
}
chainShouldBreak =
chainShouldBreak ||
// Always break the chain if:
(n.returnType && getFunctionParameters(n).length > 0) ||
n.typeParameters ||
getFunctionParameters(n).some((param) => param.type !== "Identifier");
(node.returnType && getFunctionParameters(node).length > 0) ||
node.typeParameters ||
getFunctionParameters(node).some((param) => param.type !== "Identifier");
if (
n.body.type !== "ArrowFunctionExpression" ||
node.body.type !== "ArrowFunctionExpression" ||
(args && args.expandLastArg)
) {
body = path.call((bodyPath) => print(bodyPath, args), "body");
body.unshift(print("body", args));
} else {
n = n.body;
node = node.body;
path.call(rec, "body");
}
});
})();
if (signatures.length > 1) {
return printArrowChain(path, args, signatures, chainShouldBreak, body, n);
return printArrowChain(
path,
args,
signatures,
chainShouldBreak,
body,
node
);
}
const parts = signatures;
@@ -281,21 +302,21 @@ function printArrowFunctionExpression(path, options, print, args) {
// We want to always keep these types of nodes on the same line
// as the arrow.
if (
!hasLeadingOwnLineComment(options.originalText, n.body) &&
(n.body.type === "ArrayExpression" ||
n.body.type === "ObjectExpression" ||
n.body.type === "BlockStatement" ||
isJsxNode(n.body) ||
isTemplateOnItsOwnLine(n.body, options.originalText) ||
n.body.type === "ArrowFunctionExpression" ||
n.body.type === "DoExpression")
!hasLeadingOwnLineComment(options.originalText, node.body) &&
(node.body.type === "ArrayExpression" ||
node.body.type === "ObjectExpression" ||
node.body.type === "BlockStatement" ||
isJsxNode(node.body) ||
isTemplateOnItsOwnLine(node.body, options.originalText) ||
node.body.type === "ArrowFunctionExpression" ||
node.body.type === "DoExpression")
) {
return group([...parts, " ", body]);
}
// We handle sequence expressions as the body of arrows specially,
// so that the required parentheses end up on their own lines.
if (n.body.type === "SequenceExpression") {
if (node.body.type === "SequenceExpression") {
return group([
...parts,
group([" (", indent([softline, body]), softline, ")"]),
@@ -309,7 +330,7 @@ function printArrowFunctionExpression(path, options, print, args) {
const shouldAddSoftLine =
((args && args.expandLastArg) ||
path.getParentNode().type === "JSXExpressionContainer") &&
!hasComment(n);
!hasComment(node);
const printTrailingComma =
args && args.expandLastArg && shouldPrintComma(options, "all");
@@ -318,8 +339,8 @@ function printArrowFunctionExpression(path, options, print, args) {
// a => a ? a : a
// a <= a ? a : a
const shouldAddParens =
n.body.type === "ConditionalExpression" &&
!startsWithNoLookaheadToken(n.body, /* forbidFunctionAndClass */ false);
node.body.type === "ConditionalExpression" &&
!startsWithNoLookaheadToken(node.body, /* forbidFunctionAndClass */ false);
return group([
...parts,
@@ -368,12 +389,12 @@ function shouldPrintParamsWithoutParens(path, options) {
}
function printReturnType(path, print, options) {
const n = path.getValue();
const returnType = path.call(print, "returnType");
const node = path.getValue();
const returnType = print("returnType");
if (
n.returnType &&
isFlowAnnotationComment(options.originalText, n.returnType)
node.returnType &&
isFlowAnnotationComment(options.originalText, node.returnType)
) {
return [" /*: ", returnType, " */"];
}
@@ -381,14 +402,14 @@ function printReturnType(path, print, options) {
const parts = [returnType];
// prepend colon to TypeScript type annotation
if (n.returnType && n.returnType.typeAnnotation) {
if (node.returnType && node.returnType.typeAnnotation) {
parts.unshift(": ");
}
if (n.predicate) {
if (node.predicate) {
// The return type will already add the colon, but otherwise we
// need to do it ourselves
parts.push(n.returnType ? " " : ": ", path.call(print, "predicate"));
parts.push(node.returnType ? " " : ": ", print("predicate"));
}
return parts;
@@ -402,12 +423,7 @@ function printReturnAndThrowArgument(path, options, print) {
if (node.argument) {
if (returnArgumentHasLeadingComment(options, node.argument)) {
parts.push([
" (",
indent([hardline, path.call(print, "argument")]),
hardline,
")",
]);
parts.push([" (", indent([hardline, print("argument")]), hardline, ")"]);
} else if (
isBinaryish(node.argument) ||
node.argument.type === "SequenceExpression"
@@ -415,18 +431,18 @@ function printReturnAndThrowArgument(path, options, print) {
parts.push(
group([
ifBreak(" (", " "),
indent([softline, path.call(print, "argument")]),
indent([softline, print("argument")]),
softline,
ifBreak(")"),
])
);
} else {
parts.push(" ", path.call(print, "argument"));
parts.push(" ", print("argument"));
}
}
const comments = getComments(node);
const lastComment = comments[comments.length - 1];
const lastComment = getLast(comments);
const isLastCommentLine = lastComment && isLineComment(lastComment);
if (isLastCommentLine) {
+14 -18
View File
@@ -9,15 +9,15 @@ const { getTypeParametersGroupId } = require("./type-parameters");
const { printTypeScriptModifiers } = require("./misc");
function printInterface(path, options, print) {
const n = path.getValue();
const node = path.getValue();
const parts = [];
if (n.declare) {
if (node.declare) {
parts.push("declare ");
}
if (n.type === "TSInterfaceDeclaration") {
if (node.type === "TSInterfaceDeclaration") {
parts.push(
n.abstract ? "abstract " : "",
node.abstract ? "abstract " : "",
printTypeScriptModifiers(path, options, print)
);
}
@@ -27,38 +27,34 @@ function printInterface(path, options, print) {
const partsGroup = [];
const extendsParts = [];
if (n.type !== "InterfaceTypeAnnotation") {
partsGroup.push(
" ",
path.call(print, "id"),
path.call(print, "typeParameters")
);
if (node.type !== "InterfaceTypeAnnotation") {
partsGroup.push(" ", print("id"), print("typeParameters"));
}
const shouldIndentOnlyHeritageClauses =
n.typeParameters &&
node.typeParameters &&
!hasComment(
n.typeParameters,
node.typeParameters,
CommentCheckFlags.Trailing | CommentCheckFlags.Line
);
if (isNonEmptyArray(n.extends)) {
if (isNonEmptyArray(node.extends)) {
extendsParts.push(
shouldIndentOnlyHeritageClauses
? ifBreak(" ", line, {
groupId: getTypeParametersGroupId(n.typeParameters),
groupId: getTypeParametersGroupId(node.typeParameters),
})
: line,
"extends ",
(n.extends.length === 1 ? identity : indent)(
(node.extends.length === 1 ? identity : indent)(
join([",", line], path.map(print, "extends"))
)
);
}
if (
(n.id && hasComment(n.id, CommentCheckFlags.Trailing)) ||
isNonEmptyArray(n.extends)
(node.id && hasComment(node.id, CommentCheckFlags.Trailing)) ||
isNonEmptyArray(node.extends)
) {
if (shouldIndentOnlyHeritageClauses) {
parts.push(group([...partsGroup, indent(extendsParts)]));
@@ -69,7 +65,7 @@ function printInterface(path, options, print) {
parts.push(...partsGroup, ...extendsParts);
}
parts.push(" ", path.call(print, "body"));
parts.push(" ", print("body"));
return group(parts);
}
+92 -108
View File
@@ -57,29 +57,26 @@ const isEmptyStringOrAnyLine = (doc) =>
// To support that case properly, all leading and trailing spaces
// are stripped from the list of children, and replaced with a single hardline.
function printJsxElementInternal(path, options, print) {
const n = path.getValue();
const node = path.getValue();
if (n.type === "JSXElement" && isEmptyJsxElement(n)) {
return [
path.call(print, "openingElement"),
path.call(print, "closingElement"),
];
if (node.type === "JSXElement" && isEmptyJsxElement(node)) {
return [print("openingElement"), print("closingElement")];
}
const openingLines =
n.type === "JSXElement"
? path.call(print, "openingElement")
: path.call(print, "openingFragment");
node.type === "JSXElement"
? print("openingElement")
: print("openingFragment");
const closingLines =
n.type === "JSXElement"
? path.call(print, "closingElement")
: path.call(print, "closingFragment");
node.type === "JSXElement"
? print("closingElement")
: print("closingFragment");
if (
n.children.length === 1 &&
n.children[0].type === "JSXExpressionContainer" &&
(n.children[0].expression.type === "TemplateLiteral" ||
n.children[0].expression.type === "TaggedTemplateExpression")
node.children.length === 1 &&
node.children[0].type === "JSXExpressionContainer" &&
(node.children[0].expression.type === "TemplateLiteral" ||
node.children[0].expression.type === "TaggedTemplateExpression")
) {
return [openingLines, ...path.map(print, "children"), closingLines];
}
@@ -87,7 +84,7 @@ function printJsxElementInternal(path, options, print) {
// Convert `{" "}` to text nodes containing a space.
// This makes it easy to turn them into `jsxWhitespace` which
// can then print as either a space or `{" "}` when breaking.
n.children = n.children.map((child) => {
node.children = node.children.map((child) => {
if (isJsxWhitespaceExpression(child)) {
return {
type: "JSXText",
@@ -98,12 +95,12 @@ function printJsxElementInternal(path, options, print) {
return child;
});
const containsTag = n.children.filter(isJsxNode).length > 0;
const containsTag = node.children.filter(isJsxNode).length > 0;
const containsMultipleExpressions =
n.children.filter((child) => child.type === "JSXExpressionContainer")
node.children.filter((child) => child.type === "JSXExpressionContainer")
.length > 1;
const containsMultipleAttributes =
n.type === "JSXElement" && n.openingElement.attributes.length > 1;
node.type === "JSXElement" && node.openingElement.attributes.length > 1;
// Record any breaks. Should never go from true to false, only false to true.
let forcedBreak =
@@ -120,9 +117,9 @@ function printJsxElementInternal(path, options, print) {
: ifBreak([rawJsxWhitespace, softline], " ");
const isFacebookTranslationTag =
n.openingElement &&
n.openingElement.name &&
n.openingElement.name.name === "fbt";
node.openingElement &&
node.openingElement.name &&
node.openingElement.name.name === "fbt";
const children = printJsxChildren(
path,
@@ -132,7 +129,9 @@ function printJsxElementInternal(path, options, print) {
isFacebookTranslationTag
);
const containsText = n.children.some((child) => isMeaningfulJsxText(child));
const containsText = node.children.some((child) =>
isMeaningfulJsxText(child)
);
// We can end up we multiple whitespace elements with empty string
// content between them.
@@ -358,7 +357,7 @@ function printJsxChildren(
parts.push("", jsxWhitespace);
}
} else {
const printedChild = print(childPath);
const printedChild = print();
parts.push(printedChild);
const next = children[i + 1];
@@ -469,14 +468,14 @@ function maybeWrapJsxElementInParens(path, elem, options) {
}
function printJsxAttribute(path, options, print) {
const n = path.getValue();
const node = path.getValue();
const parts = [];
parts.push(path.call(print, "name"));
parts.push(print("name"));
if (n.value) {
if (node.value) {
let res;
if (isStringLiteral(n.value)) {
const raw = rawText(n.value);
if (isStringLiteral(node.value)) {
const raw = rawText(node.value);
// Unescape all quotes so we get an accurate preferred quote
let final = raw.replace(/&apos;/g, "'").replace(/&quot;/g, '"');
const quote = getPreferredQuote(
@@ -487,7 +486,7 @@ function printJsxAttribute(path, options, print) {
final = final.slice(1, -1).replace(new RegExp(quote, "g"), escape);
res = [quote, final, quote];
} else {
res = path.call(print, "value");
res = print("value");
}
parts.push("=", res);
}
@@ -496,36 +495,31 @@ function printJsxAttribute(path, options, print) {
}
function printJsxExpressionContainer(path, options, print) {
const n = path.getValue();
const node = path.getValue();
const parent = path.getParentNode(0);
const shouldInline =
n.expression.type === "JSXEmptyExpression" ||
(!hasComment(n.expression) &&
(n.expression.type === "ArrayExpression" ||
n.expression.type === "ObjectExpression" ||
n.expression.type === "ArrowFunctionExpression" ||
isCallExpression(n.expression) ||
n.expression.type === "FunctionExpression" ||
n.expression.type === "TemplateLiteral" ||
n.expression.type === "TaggedTemplateExpression" ||
n.expression.type === "DoExpression" ||
node.expression.type === "JSXEmptyExpression" ||
(!hasComment(node.expression) &&
(node.expression.type === "ArrayExpression" ||
node.expression.type === "ObjectExpression" ||
node.expression.type === "ArrowFunctionExpression" ||
isCallExpression(node.expression) ||
node.expression.type === "FunctionExpression" ||
node.expression.type === "TemplateLiteral" ||
node.expression.type === "TaggedTemplateExpression" ||
node.expression.type === "DoExpression" ||
(isJsxNode(parent) &&
(n.expression.type === "ConditionalExpression" ||
isBinaryish(n.expression)))));
(node.expression.type === "ConditionalExpression" ||
isBinaryish(node.expression)))));
if (shouldInline) {
return group([
"{",
path.call(print, "expression"),
lineSuffixBoundary,
"}",
]);
return group(["{", print("expression"), lineSuffixBoundary, "}"]);
}
return group([
"{",
indent([softline, path.call(print, "expression")]),
indent([softline, print("expression")]),
softline,
lineSuffixBoundary,
"}",
@@ -533,29 +527,24 @@ function printJsxExpressionContainer(path, options, print) {
}
function printJsxOpeningElement(path, options, print) {
const n = path.getValue();
const node = path.getValue();
const nameHasComments =
(n.name && hasComment(n.name)) ||
(n.typeParameters && hasComment(n.typeParameters));
(node.name && hasComment(node.name)) ||
(node.typeParameters && hasComment(node.typeParameters));
// Don't break self-closing elements with no attributes and no comments
if (n.selfClosing && n.attributes.length === 0 && !nameHasComments) {
return [
"<",
path.call(print, "name"),
path.call(print, "typeParameters"),
" />",
];
if (node.selfClosing && node.attributes.length === 0 && !nameHasComments) {
return ["<", print("name"), print("typeParameters"), " />"];
}
// don't break up opening elements with a single long text attribute
if (
n.attributes &&
n.attributes.length === 1 &&
n.attributes[0].value &&
isStringLiteral(n.attributes[0].value) &&
!n.attributes[0].value.value.includes("\n") &&
node.attributes &&
node.attributes.length === 1 &&
node.attributes[0].value &&
isStringLiteral(node.attributes[0].value) &&
!node.attributes[0].value.value.includes("\n") &&
// We should break for the following cases:
// <div
// // comment
@@ -566,26 +555,26 @@ function printJsxOpeningElement(path, options, print) {
// // comment
// >
!nameHasComments &&
!hasComment(n.attributes[0])
!hasComment(node.attributes[0])
) {
return group([
"<",
path.call(print, "name"),
path.call(print, "typeParameters"),
print("name"),
print("typeParameters"),
" ",
...path.map(print, "attributes"),
n.selfClosing ? " />" : ">",
node.selfClosing ? " />" : ">",
]);
}
const lastAttrHasTrailingComments =
n.attributes.length > 0 &&
hasComment(getLast(n.attributes), CommentCheckFlags.Trailing);
node.attributes.length > 0 &&
hasComment(getLast(node.attributes), CommentCheckFlags.Trailing);
const bracketSameLine =
// Simple tags (no attributes and no comment in tag name) should be
// kept unbroken regardless of `jsxBracketSameLine`
(n.attributes.length === 0 && !nameHasComments) ||
(node.attributes.length === 0 && !nameHasComments) ||
(options.jsxBracketSameLine &&
// We should print the bracket in a new line for the following cases:
// <div
@@ -594,14 +583,14 @@ function printJsxOpeningElement(path, options, print) {
// <div
// attr // comment
// >
(!nameHasComments || n.attributes.length > 0) &&
(!nameHasComments || node.attributes.length > 0) &&
!lastAttrHasTrailingComments);
// We should print the opening element expanded if any prop value is a
// string literal with newlines
const shouldBreak =
n.attributes &&
n.attributes.some(
node.attributes &&
node.attributes.some(
(attr) =>
attr.value &&
isStringLiteral(attr.value) &&
@@ -611,28 +600,29 @@ function printJsxOpeningElement(path, options, print) {
return group(
[
"<",
path.call(print, "name"),
path.call(print, "typeParameters"),
indent(path.map((attr) => [line, print(attr)], "attributes")),
n.selfClosing ? line : bracketSameLine ? ">" : softline,
n.selfClosing ? "/>" : bracketSameLine ? "" : ">",
print("name"),
print("typeParameters"),
indent(path.map(() => [line, print()], "attributes")),
node.selfClosing ? line : bracketSameLine ? ">" : softline,
node.selfClosing ? "/>" : bracketSameLine ? "" : ">",
],
{ shouldBreak }
);
}
function printJsxClosingElement(path, options, print) {
const n = path.getValue();
const node = path.getValue();
const parts = [];
parts.push("</");
const printed = path.call(print, "name");
if (hasComment(n.name, CommentCheckFlags.Leading | CommentCheckFlags.Line)) {
const printed = print("name");
if (
hasComment(node.name, CommentCheckFlags.Leading | CommentCheckFlags.Line)
) {
parts.push(indent([hardline, printed]), hardline);
} else if (
hasComment(n.name, CommentCheckFlags.Leading | CommentCheckFlags.Block)
hasComment(node.name, CommentCheckFlags.Leading | CommentCheckFlags.Block)
) {
parts.push(" ", printed);
} else {
@@ -645,10 +635,10 @@ function printJsxClosingElement(path, options, print) {
}
function printJsxOpeningClosingFragment(path, options /*, print*/) {
const n = path.getValue();
const nodeHasComment = hasComment(n);
const hasOwnLineComment = hasComment(n, CommentCheckFlags.Line);
const isOpeningFragment = n.type === "JSXOpeningFragment";
const node = path.getValue();
const nodeHasComment = hasComment(node);
const hasOwnLineComment = hasComment(node, CommentCheckFlags.Line);
const isOpeningFragment = node.type === "JSXOpeningFragment";
return [
isOpeningFragment ? "<" : "</",
indent([
@@ -674,8 +664,8 @@ function printJsxElement(path, options, print) {
}
function printJsxEmptyExpression(path, options /*, print*/) {
const n = path.getValue();
const requiresHardline = hasComment(n, CommentCheckFlags.Line);
const node = path.getValue();
const requiresHardline = hasComment(node, CommentCheckFlags.Line);
return [
printDanglingComments(path, options, /* sameIndent */ !requiresHardline),
@@ -685,14 +675,14 @@ function printJsxEmptyExpression(path, options /*, print*/) {
// `JSXSpreadAttribute` and `JSXSpreadChild`
function printJsxSpreadAttribute(path, options, print) {
const n = path.getValue();
const node = path.getValue();
return [
"{",
path.call(
(p) => {
const printed = ["...", print(p)];
const n = p.getValue();
if (!hasComment(n) || !willPrintOwnComments(p)) {
const printed = ["...", print()];
const node = p.getValue();
if (!hasComment(node) || !willPrintOwnComments(p)) {
return printed;
}
return [
@@ -700,29 +690,23 @@ function printJsxSpreadAttribute(path, options, print) {
softline,
];
},
n.type === "JSXSpreadAttribute" ? "argument" : "expression"
node.type === "JSXSpreadAttribute" ? "argument" : "expression"
),
"}",
];
}
function printJsx(path, options, print) {
const n = path.getValue();
switch (n.type) {
const node = path.getValue();
switch (node.type) {
case "JSXAttribute":
return printJsxAttribute(path, options, print);
case "JSXIdentifier":
return String(n.name);
return String(node.name);
case "JSXNamespacedName":
return join(":", [
path.call(print, "namespace"),
path.call(print, "name"),
]);
return join(":", [print("namespace"), print("name")]);
case "JSXMemberExpression":
return join(".", [
path.call(print, "object"),
path.call(print, "property"),
]);
return join(".", [print("object"), print("property")]);
case "JSXSpreadAttribute":
return printJsxSpreadAttribute(path, options, print);
case "JSXSpreadChild": {
+3 -6
View File
@@ -135,7 +135,7 @@ function printMemberChain(path, options, print) {
} else {
printedNodes.unshift({
node,
printed: path.call(print),
printed: print(),
});
}
}
@@ -309,10 +309,7 @@ function printMemberChain(path, options, print) {
const printed = printedGroup.map((tuple) => tuple.printed);
// Checks if the last node (i.e. the parent node) needs parens and print
// accordingly
if (
printedGroup.length > 0 &&
printedGroup[printedGroup.length - 1].needsParens
) {
if (printedGroup.length > 0 && getLast(printedGroup).needsParens) {
return ["(", ...printed, ")"];
}
return printed;
@@ -377,7 +374,7 @@ function printMemberChain(path, options, print) {
willBreak(lastGroupDoc) &&
callExpressions
.slice(0, -1)
.some((n) => n.arguments.some(isFunctionOrArrowExpression))
.some((node) => node.arguments.some(isFunctionOrArrowExpression))
);
}
+9 -9
View File
@@ -7,7 +7,7 @@ const { isNumericLiteral, isMemberExpression } = require("../utils");
const { printOptionalToken } = require("./misc");
function printMemberExpression(path, options, print) {
const n = path.getValue();
const node = path.getValue();
const parent = path.getParentNode();
let firstNonMemberParent;
@@ -27,13 +27,13 @@ function printMemberExpression(path, options, print) {
firstNonMemberParent.type === "BindExpression" ||
(firstNonMemberParent.type === "AssignmentExpression" &&
firstNonMemberParent.left.type !== "Identifier"))) ||
n.computed ||
(n.object.type === "Identifier" &&
n.property.type === "Identifier" &&
node.computed ||
(node.object.type === "Identifier" &&
node.property.type === "Identifier" &&
!isMemberExpression(parent));
return [
path.call(print, "object"),
print("object"),
shouldInline
? printMemberLookup(path, options, print)
: group(indent([softline, printMemberLookup(path, options, print)])),
@@ -41,15 +41,15 @@ function printMemberExpression(path, options, print) {
}
function printMemberLookup(path, options, print) {
const property = path.call(print, "property");
const n = path.getValue();
const property = print("property");
const node = path.getValue();
const optional = printOptionalToken(path);
if (!n.computed) {
if (!node.computed) {
return [optional, ".", property];
}
if (!n.property || isNumericLiteral(n.property)) {
if (!node.property || isNumericLiteral(node.property)) {
return [optional, "[", property, "]"];
}
+7 -7
View File
@@ -28,10 +28,10 @@ function printOptionalToken(path) {
function printFunctionTypeParameters(path, options, print) {
const fun = path.getValue();
if (fun.typeArguments) {
return path.call(print, "typeArguments");
return print("typeArguments");
}
if (fun.typeParameters) {
return path.call(print, "typeParameters");
return print("typeParameters");
}
return "";
}
@@ -53,22 +53,22 @@ function printTypeAnnotation(path, options, print) {
parentNode.type === "DeclareFunction" && parentNode.id === node;
if (isFlowAnnotationComment(options.originalText, node.typeAnnotation)) {
return [" /*: ", path.call(print, "typeAnnotation"), " */"];
return [" /*: ", print("typeAnnotation"), " */"];
}
return [
isFunctionDeclarationIdentifier ? "" : isDefinite ? "!: " : ": ",
path.call(print, "typeAnnotation"),
print("typeAnnotation"),
];
}
function printBindExpressionCallee(path, options, print) {
return ["::", path.call(print, "callee")];
return ["::", print("callee")];
}
function printTypeScriptModifiers(path, options, print) {
const n = path.getValue();
if (!isNonEmptyArray(n.modifiers)) {
const node = path.getValue();
if (!isNonEmptyArray(node.modifiers)) {
return "";
}
return [join(" ", path.map(print, "modifiers")), " "];
+8 -8
View File
@@ -78,7 +78,7 @@ function printExportDeclaration(path, options, print) {
}
if (declaration) {
parts.push(" ", path.call(print, "declaration"));
parts.push(" ", print("declaration"));
} else {
parts.push(
exportKind === "type" ? " type" : "",
@@ -112,7 +112,7 @@ function printExportAllDeclaration(path, options, print) {
parts.push(" *");
if (exported) {
parts.push(" as ", path.call(print, "exported"));
parts.push(" as ", print("exported"));
}
parts.push(
@@ -163,7 +163,7 @@ function printModuleSource(path, options, print) {
if (!shouldNotPrintSpecifiers(node, options)) {
parts.push(" from");
}
parts.push(" ", path.call(print, "source"));
parts.push(" ", print("source"));
return parts;
}
@@ -182,7 +182,7 @@ function printModuleSpecifiers(path, options, print) {
const standaloneSpecifiers = [];
const groupedSpecifiers = [];
path.each((specifierPath) => {
path.each(() => {
const specifierType = path.getValue().type;
if (
specifierType === "ExportNamespaceSpecifier" ||
@@ -190,12 +190,12 @@ function printModuleSpecifiers(path, options, print) {
specifierType === "ImportNamespaceSpecifier" ||
specifierType === "ImportDefaultSpecifier"
) {
standaloneSpecifiers.push(print(specifierPath));
standaloneSpecifiers.push(print());
} else if (
specifierType === "ExportSpecifier" ||
specifierType === "ImportSpecifier"
) {
groupedSpecifiers.push(print(specifierPath));
groupedSpecifiers.push(print());
} else {
/* istanbul ignore next */
throw new Error(
@@ -297,7 +297,7 @@ function printModuleSpecifier(path, options, print) {
) {
left = "*";
} else if (node[leftSideProperty]) {
left = path.call(print, leftSideProperty);
left = print(leftSideProperty);
}
if (
@@ -306,7 +306,7 @@ function printModuleSpecifier(path, options, print) {
// import {a as a} from '.'
!hasSameLoc(node[leftSideProperty], node[rightSideProperty]))
) {
right = path.call(print, rightSideProperty);
right = print(rightSideProperty);
}
parts.push(left, left && right ? " as " : "", right);
+23 -22
View File
@@ -28,19 +28,19 @@ const { printHardlineAfterHeritage } = require("./class");
function printObject(path, options, print) {
const semi = options.semi ? ";" : "";
const n = path.getValue();
const node = path.getValue();
let propertiesField;
if (n.type === "TSTypeLiteral") {
if (node.type === "TSTypeLiteral") {
propertiesField = "members";
} else if (n.type === "TSInterfaceBody") {
} else if (node.type === "TSInterfaceBody") {
propertiesField = "body";
} else {
propertiesField = "properties";
}
const isTypeAnnotation = n.type === "ObjectTypeAnnotation";
const isTypeAnnotation = node.type === "ObjectTypeAnnotation";
const fields = [];
if (isTypeAnnotation) {
fields.push("indexers", "callProperties", "internalSlots");
@@ -48,7 +48,7 @@ function printObject(path, options, print) {
fields.push(propertiesField);
const firstProperty = fields
.map((field) => n[field][0])
.map((field) => node[field][0])
.sort((a, b) => locStart(a) - locStart(b))[0];
const parent = path.getParentNode(0);
@@ -60,9 +60,9 @@ function printObject(path, options, print) {
parent.type === "DeclareClass") &&
path.getName() === "body";
const shouldBreak =
n.type === "TSInterfaceBody" ||
node.type === "TSInterfaceBody" ||
isFlowInterfaceLikeBody ||
(n.type === "ObjectPattern" &&
(node.type === "ObjectPattern" &&
parent.type !== "FunctionDeclaration" &&
parent.type !== "FunctionExpression" &&
parent.type !== "ArrowFunctionExpression" &&
@@ -71,27 +71,28 @@ function printObject(path, options, print) {
parent.type !== "ClassPrivateMethod" &&
parent.type !== "AssignmentPattern" &&
parent.type !== "CatchClause" &&
n.properties.some(
node.properties.some(
(property) =>
property.value &&
(property.value.type === "ObjectPattern" ||
property.value.type === "ArrayPattern")
)) ||
(n.type !== "ObjectPattern" &&
(node.type !== "ObjectPattern" &&
firstProperty &&
hasNewlineInRange(
options.originalText,
locStart(n),
locStart(node),
locStart(firstProperty)
));
const separator = isFlowInterfaceLikeBody
? ";"
: n.type === "TSInterfaceBody" || n.type === "TSTypeLiteral"
: node.type === "TSInterfaceBody" || node.type === "TSTypeLiteral"
? ifBreak(semi, ";")
: ",";
const leftBrace = n.type === "RecordExpression" ? "#{" : n.exact ? "{|" : "{";
const rightBrace = n.exact ? "|}" : "}";
const leftBrace =
node.type === "RecordExpression" ? "#{" : node.exact ? "{|" : "{";
const rightBrace = node.exact ? "|}" : "}";
// Unfortunately, things are grouped together in the ast can be
// interleaved in the source code. So we need to reorder them before
@@ -102,7 +103,7 @@ function printObject(path, options, print) {
const node = childPath.getValue();
propsAndLoc.push({
node,
printed: print(childPath),
printed: print(),
loc: locStart(node),
});
}, field);
@@ -129,10 +130,10 @@ function printObject(path, options, print) {
return result;
});
if (n.inexact) {
if (node.inexact) {
let printed;
if (hasComment(n, CommentCheckFlags.Dangling)) {
const hasLineComments = hasComment(n, CommentCheckFlags.Line);
if (hasComment(node, CommentCheckFlags.Dangling)) {
const hasLineComments = hasComment(node, CommentCheckFlags.Line);
const printedDanglingComments = printDanglingComments(
path,
options,
@@ -141,7 +142,7 @@ function printObject(path, options, print) {
printed = [
printedDanglingComments,
hasLineComments ||
hasNewline(options.originalText, locEnd(getLast(getComments(n))))
hasNewline(options.originalText, locEnd(getLast(getComments(node))))
? hardline
: line,
"...",
@@ -152,10 +153,10 @@ function printObject(path, options, print) {
props.push([...separatorParts, ...printed]);
}
const lastElem = getLast(n[propertiesField]);
const lastElem = getLast(node[propertiesField]);
const canHaveTrailingSeparator = !(
n.inexact ||
node.inexact ||
(lastElem && lastElem.type === "RestElement") ||
(lastElem &&
(lastElem.type === "TSPropertySignature" ||
@@ -167,7 +168,7 @@ function printObject(path, options, print) {
let content;
if (props.length === 0) {
if (!hasComment(n, CommentCheckFlags.Dangling)) {
if (!hasComment(node, CommentCheckFlags.Dangling)) {
return [leftBrace, rightBrace, printTypeAnnotation(path, options, print)];
}
@@ -181,7 +182,7 @@ function printObject(path, options, print) {
]);
} else {
content = [
isFlowInterfaceLikeBody && isNonEmptyArray(n.properties)
isFlowInterfaceLikeBody && isNonEmptyArray(node.properties)
? printHardlineAfterHeritage(parent)
: "",
leftBrace,
+6 -6
View File
@@ -17,7 +17,7 @@ function printPropertyKey(path, options, print) {
const node = path.getNode();
if (node.computed) {
return ["[", path.call(print, "key"), "]"];
return ["[", print("key"), "]"];
}
const parent = path.getParentNode();
@@ -25,7 +25,7 @@ function printPropertyKey(path, options, print) {
// flow has `Identifier` key, other parsers use `PrivateIdentifier` (ESTree) or `PrivateName`
if (node.type === "ClassPrivateProperty" && key.type === "Identifier") {
return ["#", path.call(print, "key")];
return ["#", print("key")];
}
if (options.quoteProps === "consistent" && !needsQuoteProps.has(parent)) {
@@ -86,13 +86,13 @@ function printPropertyKey(path, options, print) {
);
}
return path.call(print, "key");
return print("key");
}
function printProperty(path, options, print) {
const n = path.getValue();
if (n.shorthand) {
return path.call(print, "value");
const node = path.getValue();
if (node.shorthand) {
return print("value");
}
return printAssignment(
+2 -2
View File
@@ -35,7 +35,7 @@ function printStatementSequence(path, options, print, property) {
return;
}
const printed = print(path);
const printed = print();
// in no-semi mode, prepend statement with semicolon if it might break ASI
// don't prepend the only JSX element in a program with semicolon
@@ -46,7 +46,7 @@ function printStatementSequence(path, options, print, property) {
statementNeedsASIProtection(path, options)
) {
if (hasComment(node, CommentCheckFlags.Leading)) {
parts.push(print(path, { needsSemi: true }));
parts.push(print([], { needsSemi: true }));
} else {
parts.push(";", printed);
}
+4 -3
View File
@@ -1,5 +1,6 @@
"use strict";
const getLast = require("../../utils/get-last");
const { getStringWidth, getIndentSize } = require("../../common/util");
const {
builders: {
@@ -60,7 +61,7 @@ function printTemplateLiteral(path, print, options) {
path.each((childPath) => {
const i = childPath.getName();
parts.push(print(childPath));
parts.push(print());
if (i < expressions.length) {
// For a template literal of the following form:
@@ -140,7 +141,7 @@ function printJestEachTemplateLiteral(path, options, print) {
const tableBody = [{ hasLineBreak: false, cells: [] }];
for (let i = 1; i < node.quasis.length; i++) {
const row = tableBody[tableBody.length - 1];
const row = getLast(tableBody);
const correspondingExpression = stringifiedExpressions[i - 1];
row.cells.push(correspondingExpression);
@@ -201,7 +202,7 @@ function printJestEachTemplateLiteral(path, options, print) {
function printTemplateExpression(path, print) {
const node = path.getValue();
let printed = print(path);
let printed = print();
if (hasComment(node)) {
printed = group([indent([softline, printed]), softline]);
}
+9 -15
View File
@@ -116,14 +116,8 @@ function printTernaryTest(path, options, print) {
const parent = path.getParentNode();
const printed = isConditionalExpression
? path.call(print, "test")
: [
path.call(print, "checkType"),
" ",
"extends",
" ",
path.call(print, "extendsType"),
];
? print("test")
: [print("checkType"), " ", "extends", " ", print("extendsType")];
/**
* a
* ? b
@@ -275,12 +269,12 @@ function printTernary(path, options, print) {
parts.push(
" ? ",
isNil(consequentNode)
? path.call(print, consequentNodePropertyName)
: wrap(path.call(print, consequentNodePropertyName)),
? print(consequentNodePropertyName)
: wrap(print(consequentNodePropertyName)),
" : ",
alternateNode.type === node.type || isNil(alternateNode)
? path.call(print, alternateNodePropertyName)
: wrap(path.call(print, alternateNodePropertyName))
? print(alternateNodePropertyName)
: wrap(print(alternateNodePropertyName))
);
} else {
// normal mode
@@ -288,13 +282,13 @@ function printTernary(path, options, print) {
line,
"? ",
consequentNode.type === node.type ? ifBreak("", "(") : "",
align(2, path.call(print, consequentNodePropertyName)),
align(2, print(consequentNodePropertyName)),
consequentNode.type === node.type ? ifBreak("", ")") : "",
line,
": ",
alternateNode.type === node.type
? path.call(print, alternateNodePropertyName)
: align(2, path.call(print, alternateNodePropertyName)),
? print(alternateNodePropertyName)
: align(2, print(alternateNodePropertyName)),
];
parts.push(
parent.type !== node.type ||
+52 -47
View File
@@ -28,20 +28,20 @@ function shouldHugType(node) {
if (node.type === "UnionTypeAnnotation" || node.type === "TSUnionType") {
const voidCount = node.types.filter(
(n) =>
n.type === "VoidTypeAnnotation" ||
n.type === "TSVoidKeyword" ||
n.type === "NullLiteralTypeAnnotation" ||
n.type === "TSNullKeyword"
(node) =>
node.type === "VoidTypeAnnotation" ||
node.type === "TSVoidKeyword" ||
node.type === "NullLiteralTypeAnnotation" ||
node.type === "TSNullKeyword"
).length;
const hasObject = node.types.some(
(n) =>
n.type === "ObjectTypeAnnotation" ||
n.type === "TSTypeLiteral" ||
(node) =>
node.type === "ObjectTypeAnnotation" ||
node.type === "TSTypeLiteral" ||
// This is a bit aggressive but captures Array<{x}>
n.type === "GenericTypeAnnotation" ||
n.type === "TSTypeReference"
node.type === "GenericTypeAnnotation" ||
node.type === "TSTypeReference"
);
if (node.types.length - 1 === voidCount && hasObject) {
@@ -54,20 +54,16 @@ function shouldHugType(node) {
function printOpaqueType(path, options, print) {
const semi = options.semi ? ";" : "";
const n = path.getValue();
const node = path.getValue();
const parts = [];
parts.push(
"opaque type ",
path.call(print, "id"),
path.call(print, "typeParameters")
);
parts.push("opaque type ", print("id"), print("typeParameters"));
if (n.supertype) {
parts.push(": ", path.call(print, "supertype"));
if (node.supertype) {
parts.push(": ", print("supertype"));
}
if (n.impltype) {
parts.push(" = ", path.call(print, "impltype"));
if (node.impltype) {
parts.push(" = ", print("impltype"));
}
parts.push(semi);
@@ -77,18 +73,14 @@ function printOpaqueType(path, options, print) {
function printTypeAlias(path, options, print) {
const semi = options.semi ? ";" : "";
const n = path.getValue();
const node = path.getValue();
const parts = [];
if (n.declare) {
if (node.declare) {
parts.push("declare ");
}
parts.push(
"type ",
path.call(print, "id"),
path.call(print, "typeParameters")
);
parts.push("type ", print("id"), print("typeParameters"));
const rightPropertyName =
n.type === "TSTypeAliasDeclaration" ? "typeAnnotation" : "right";
node.type === "TSTypeAliasDeclaration" ? "typeAnnotation" : "right";
return [
printAssignment(path, options, print, parts, " =", rightPropertyName),
semi,
@@ -97,17 +89,20 @@ function printTypeAlias(path, options, print) {
// `TSIntersectionType` and `IntersectionTypeAnnotation`
function printIntersectionType(path, options, print) {
const n = path.getValue();
const node = path.getValue();
const types = path.map(print, "types");
const result = [];
let wasIndented = false;
for (let i = 0; i < types.length; ++i) {
if (i === 0) {
result.push(types[i]);
} else if (isObjectType(n.types[i - 1]) && isObjectType(n.types[i])) {
} else if (isObjectType(node.types[i - 1]) && isObjectType(node.types[i])) {
// If both are objects, don't indent
result.push([" & ", wasIndented ? indent(types[i]) : types[i]]);
} else if (!isObjectType(n.types[i - 1]) && !isObjectType(n.types[i])) {
} else if (
!isObjectType(node.types[i - 1]) &&
!isObjectType(node.types[i])
) {
// If no object is involved, go to the next line if it breaks
result.push(indent([" &", line, types[i]]));
} else {
@@ -123,7 +118,7 @@ function printIntersectionType(path, options, print) {
// `TSUnionType` and `UnionTypeAnnotation`
function printUnionType(path, options, print) {
const n = path.getValue();
const node = path.getValue();
// single-line variation
// A | B | C
@@ -152,21 +147,21 @@ function printUnionType(path, options, print) {
(parent.type === "TypeAlias" ||
parent.type === "VariableDeclarator" ||
parent.type === "TSTypeAliasDeclaration") &&
hasLeadingOwnLineComment(options.originalText, n)
hasLeadingOwnLineComment(options.originalText, node)
);
// {
// a: string
// } | null | void
// should be inlined and not be printed in the multi-line variant
const shouldHug = shouldHugType(n);
const shouldHug = shouldHugType(node);
// We want to align the children but without its comment, so it looks like
// | child1
// // comment
// | child2
const printed = path.map((typePath) => {
let printedType = typePath.call(print);
let printedType = print();
if (!shouldHug) {
printedType = align(2, printedType);
}
@@ -178,7 +173,7 @@ function printUnionType(path, options, print) {
}
const shouldAddStartLine =
shouldIndent && !hasLeadingOwnLineComment(options.originalText, n);
shouldIndent && !hasLeadingOwnLineComment(options.originalText, node);
const code = [
ifBreak([shouldAddStartLine ? line : "", "| "]),
@@ -205,7 +200,7 @@ function printUnionType(path, options, print) {
// `TSFunctionType` and `FunctionTypeAnnotation`
function printFunctionType(path, options, print) {
const n = path.getValue();
const node = path.getValue();
const parts = [];
// FunctionTypeAnnotation is ambiguous:
// declare function foo(a: B): void; OR
@@ -214,13 +209,13 @@ function printFunctionType(path, options, print) {
const parentParent = path.getParentNode(1);
const parentParentParent = path.getParentNode(2);
let isArrowFunctionTypeAnnotation =
n.type === "TSFunctionType" ||
node.type === "TSFunctionType" ||
!(
((parent.type === "ObjectTypeProperty" ||
parent.type === "ObjectTypeInternalSlot") &&
!parent.variance &&
!parent.optional &&
locStart(parent) === locStart(n)) ||
locStart(parent) === locStart(node)) ||
parent.type === "ObjectTypeCallProperty" ||
(parentParentParent && parentParentParent.type === "DeclareFunction")
);
@@ -258,16 +253,19 @@ function printFunctionType(path, options, print) {
// The returnType is not wrapped in a TypeAnnotation, so the colon
// needs to be added separately.
const returnTypeDoc =
n.returnType || n.predicate || n.typeAnnotation
node.returnType || node.predicate || node.typeAnnotation
? [
isArrowFunctionTypeAnnotation ? " => " : ": ",
path.call(print, "returnType"),
path.call(print, "predicate"),
path.call(print, "typeAnnotation"),
print("returnType"),
print("predicate"),
print("typeAnnotation"),
]
: "";
const shouldGroupParameters = shouldGroupFunctionParameters(n, returnTypeDoc);
const shouldGroupParameters = shouldGroupFunctionParameters(
node,
returnTypeDoc
);
parts.push(shouldGroupParameters ? group(parametersDoc) : parametersDoc);
@@ -284,10 +282,11 @@ function printFunctionType(path, options, print) {
// `TSTupleType` and `TupleTypeAnnotation`
function printTupleType(path, options, print) {
const n = path.getValue();
const typesField = n.type === "TSTupleType" ? "elementTypes" : "types";
const node = path.getValue();
const typesField = node.type === "TSTupleType" ? "elementTypes" : "types";
const hasRest =
n[typesField].length > 0 && getLast(n[typesField]).type === "TSRestType";
node[typesField].length > 0 &&
getLast(node[typesField]).type === "TSRestType";
return group([
"[",
indent([softline, printArrayItems(path, options, typesField, print)]),
@@ -298,6 +297,11 @@ function printTupleType(path, options, print) {
]);
}
// `TSIndexedAccessType` and `IndexedAccessType`
function printIndexedAccessType(path, options, print) {
return [print("objectType"), "[", print("indexType"), "]"];
}
module.exports = {
printOpaqueType,
printTypeAlias,
@@ -305,5 +309,6 @@ module.exports = {
printUnionType,
printFunctionType,
printTupleType,
printIndexedAccessType,
shouldHugType,
};
+29 -29
View File
@@ -18,15 +18,15 @@ const { shouldHugType } = require("./type-annotation");
const getTypeParametersGroupId = createGroupIdMapper("typeParameters");
function printTypeParameters(path, options, print, paramsKey) {
const n = path.getValue();
const node = path.getValue();
if (!n[paramsKey]) {
if (!node[paramsKey]) {
return "";
}
// for TypeParameterDeclaration typeParameters is a single node
if (!Array.isArray(n[paramsKey])) {
return path.call(print, paramsKey);
if (!Array.isArray(node[paramsKey])) {
return print(paramsKey);
}
const grandparent = path.getNode(2);
@@ -34,10 +34,10 @@ function printTypeParameters(path, options, print, paramsKey) {
const shouldInline =
isParameterInTestCall ||
n[paramsKey].length === 0 ||
(n[paramsKey].length === 1 &&
(shouldHugType(n[paramsKey][0]) ||
n[paramsKey][0].type === "NullableTypeAnnotation"));
node[paramsKey].length === 0 ||
(node[paramsKey].length === 1 &&
(shouldHugType(node[paramsKey][0]) ||
node[paramsKey][0].type === "NullableTypeAnnotation"));
if (shouldInline) {
return [
@@ -52,11 +52,11 @@ function printTypeParameters(path, options, print, paramsKey) {
// has one type parameter that isn't extend with any types.
// Because, otherwise formatted result will be invalid as tsx.
const trailingComma =
n.type === "TSTypeParameterInstantiation" // https://github.com/microsoft/TypeScript/issues/21984
node.type === "TSTypeParameterInstantiation" // https://github.com/microsoft/TypeScript/issues/21984
? ""
: getFunctionParameters(n).length === 1 &&
: getFunctionParameters(node).length === 1 &&
isTSXFile(options) &&
!n[paramsKey][0].constraint &&
!node[paramsKey][0].constraint &&
path.getParentNode().type === "ArrowFunctionExpression"
? ","
: shouldPrintComma(options, "all")
@@ -71,16 +71,16 @@ function printTypeParameters(path, options, print, paramsKey) {
softline,
">",
],
{ id: getTypeParametersGroupId(n) }
{ id: getTypeParametersGroupId(node) }
);
}
function printDanglingCommentsForInline(path, options) {
const n = path.getValue();
if (!hasComment(n, CommentCheckFlags.Dangling)) {
const node = path.getValue();
if (!hasComment(node, CommentCheckFlags.Dangling)) {
return "";
}
const hasOnlyBlockComments = !hasComment(n, CommentCheckFlags.Line);
const hasOnlyBlockComments = !hasComment(node, CommentCheckFlags.Line);
const printed = printDanglingComments(
path,
options,
@@ -93,40 +93,40 @@ function printDanglingCommentsForInline(path, options) {
}
function printTypeParameter(path, options, print) {
const n = path.getValue();
const node = path.getValue();
const parts = [];
const parent = path.getParentNode();
if (parent.type === "TSMappedType") {
parts.push("[", path.call(print, "name"));
if (n.constraint) {
parts.push(" in ", path.call(print, "constraint"));
parts.push("[", print("name"));
if (node.constraint) {
parts.push(" in ", print("constraint"));
}
if (parent.nameType) {
parts.push(
" as ",
path.callParent((path) => path.call(print, "nameType"))
path.callParent(() => print("nameType"))
);
}
parts.push("]");
return parts;
}
if (n.variance) {
parts.push(path.call(print, "variance"));
if (node.variance) {
parts.push(print("variance"));
}
parts.push(path.call(print, "name"));
parts.push(print("name"));
if (n.bound) {
parts.push(": ", path.call(print, "bound"));
if (node.bound) {
parts.push(": ", print("bound"));
}
if (n.constraint) {
parts.push(" extends ", path.call(print, "constraint"));
if (node.constraint) {
parts.push(" extends ", print("constraint"));
}
if (n.default) {
parts.push(" = ", path.call(print, "default"));
if (node.default) {
parts.push(" = ", print("default"));
}
return parts;
+131 -136
View File
@@ -47,46 +47,47 @@ const {
printUnionType,
printFunctionType,
printTupleType,
printIndexedAccessType,
} = require("./type-annotation");
function printTypescript(path, options, print) {
const n = path.getValue();
const node = path.getValue();
const semi = options.semi ? ";" : "";
const parts = [];
switch (n.type) {
switch (node.type) {
case "TSTypeAssertion": {
const shouldBreakAfterCast = !(
n.expression.type === "ArrayExpression" ||
n.expression.type === "ObjectExpression"
node.expression.type === "ArrayExpression" ||
node.expression.type === "ObjectExpression"
);
const castGroup = group([
"<",
indent([softline, path.call(print, "typeAnnotation")]),
indent([softline, print("typeAnnotation")]),
softline,
">",
]);
const exprContents = [
ifBreak("("),
indent([softline, path.call(print, "expression")]),
indent([softline, print("expression")]),
softline,
ifBreak(")"),
];
if (shouldBreakAfterCast) {
return conditionalGroup([
[castGroup, path.call(print, "expression")],
[castGroup, print("expression")],
[castGroup, group(exprContents, { shouldBreak: true })],
[castGroup, path.call(print, "expression")],
[castGroup, print("expression")],
]);
}
return group([castGroup, path.call(print, "expression")]);
return group([castGroup, print("expression")]);
}
case "TSDeclareFunction":
return printFunctionDeclaration(path, print, options);
case "TSExportAssignment":
return ["export = ", path.call(print, "expression"), semi];
return ["export = ", print("expression"), semi];
case "TSModuleBlock":
return printBlock(path, options, print);
case "TSInterfaceBody":
@@ -95,7 +96,7 @@ function printTypescript(path, options, print) {
case "TSTypeAliasDeclaration":
return printTypeAlias(path, options, print);
case "TSQualifiedName":
return join(".", [path.call(print, "left"), path.call(print, "right")]);
return join(".", [print("left"), print("right")]);
case "TSAbstractMethodDefinition":
case "TSDeclareMethod":
return printClassMethod(path, options, print);
@@ -103,10 +104,10 @@ function printTypescript(path, options, print) {
return printClassProperty(path, options, print);
case "TSInterfaceHeritage":
case "TSExpressionWithTypeArguments": // Babel AST
parts.push(path.call(print, "expression"));
parts.push(print("expression"));
if (n.typeParameters) {
parts.push(path.call(print, "typeParameters"));
if (node.typeParameters) {
parts.push(print("typeParameters"));
}
return parts;
@@ -114,22 +115,19 @@ function printTypescript(path, options, print) {
return printTemplateLiteral(path, print, options);
case "TSNamedTupleMember":
return [
path.call(print, "label"),
n.optional ? "?" : "",
print("label"),
node.optional ? "?" : "",
": ",
path.call(print, "elementType"),
print("elementType"),
];
case "TSRestType":
return ["...", path.call(print, "typeAnnotation")];
return ["...", print("typeAnnotation")];
case "TSOptionalType":
return [path.call(print, "typeAnnotation"), "?"];
return [print("typeAnnotation"), "?"];
case "TSInterfaceDeclaration":
return printInterface(path, options, print);
case "TSClassImplements":
return [
path.call(print, "expression"),
path.call(print, "typeParameters"),
];
return [print("expression"), print("typeParameters")];
case "TSTypeParameterDeclaration":
case "TSTypeParameterInstantiation":
return printTypeParameters(path, options, print, "params");
@@ -138,7 +136,7 @@ function printTypescript(path, options, print) {
case "TypeParameter":
return printTypeParameter(path, options, print);
case "TypeofTypeAnnotation":
return ["typeof ", path.call(print, "argument")];
return ["typeof ", print("argument")];
case "TSAbstractKeyword":
return "abstract";
case "TSAsyncKeyword":
@@ -168,33 +166,29 @@ function printTypescript(path, options, print) {
case "TSIntrinsicKeyword":
return "intrinsic";
case "TSAsExpression": {
parts.push(
path.call(print, "expression"),
" as ",
path.call(print, "typeAnnotation")
);
parts.push(print("expression"), " as ", print("typeAnnotation"));
const parent = path.getParentNode();
if (
(isCallExpression(parent) && parent.callee === n) ||
(isMemberExpression(parent) && parent.object === n)
(isCallExpression(parent) && parent.callee === node) ||
(isMemberExpression(parent) && parent.object === node)
) {
return group([indent([softline, ...parts]), softline]);
}
return parts;
}
case "TSArrayType":
return [path.call(print, "elementType"), "[]"];
return [print("elementType"), "[]"];
case "TSPropertySignature": {
if (n.export) {
if (node.export) {
parts.push("export ");
}
if (n.accessibility) {
parts.push(n.accessibility + " ");
if (node.accessibility) {
parts.push(node.accessibility + " ");
}
if (n.static) {
if (node.static) {
parts.push("static ");
}
if (n.readonly) {
if (node.readonly) {
parts.push("readonly ");
}
@@ -203,36 +197,36 @@ function printTypescript(path, options, print) {
printOptionalToken(path)
);
if (n.typeAnnotation) {
parts.push(": ", path.call(print, "typeAnnotation"));
if (node.typeAnnotation) {
parts.push(": ", print("typeAnnotation"));
}
// This isn't valid semantically, but it's in the AST so we can print it.
if (n.initializer) {
parts.push(" = ", path.call(print, "initializer"));
if (node.initializer) {
parts.push(" = ", print("initializer"));
}
return parts;
}
case "TSParameterProperty":
if (n.accessibility) {
parts.push(n.accessibility + " ");
if (node.accessibility) {
parts.push(node.accessibility + " ");
}
if (n.export) {
if (node.export) {
parts.push("export ");
}
if (n.static) {
if (node.static) {
parts.push("static ");
}
if (n.readonly) {
if (node.readonly) {
parts.push("readonly ");
}
parts.push(path.call(print, "parameter"));
parts.push(print("parameter"));
return parts;
case "TSTypeQuery":
return ["typeof ", path.call(print, "exprName")];
return ["typeof ", print("exprName")];
case "TSIndexSignature": {
const parent = path.getParentNode();
@@ -241,7 +235,7 @@ function printTypescript(path, options, print) {
// aren't, this is more like a computed property name than an array.
// So we leave off the trailing comma when there's just one parameter.
const trailingComma =
n.parameters.length > 1
node.parameters.length > 1
? ifBreak(shouldPrintComma(options) ? "," : "")
: "";
@@ -255,51 +249,46 @@ function printTypescript(path, options, print) {
]);
return [
n.export ? "export " : "",
n.accessibility ? [n.accessibility, " "] : "",
n.static ? "static " : "",
n.readonly ? "readonly " : "",
n.declare ? "declare " : "",
node.export ? "export " : "",
node.accessibility ? [node.accessibility, " "] : "",
node.static ? "static " : "",
node.readonly ? "readonly " : "",
node.declare ? "declare " : "",
"[",
n.parameters ? parametersGroup : "",
n.typeAnnotation ? "]: " : "]",
n.typeAnnotation ? path.call(print, "typeAnnotation") : "",
node.parameters ? parametersGroup : "",
node.typeAnnotation ? "]: " : "]",
node.typeAnnotation ? print("typeAnnotation") : "",
parent.type === "ClassBody" ? semi : "",
];
}
case "TSTypePredicate":
return [
n.asserts ? "asserts " : "",
path.call(print, "parameterName"),
n.typeAnnotation ? [" is ", path.call(print, "typeAnnotation")] : "",
node.asserts ? "asserts " : "",
print("parameterName"),
node.typeAnnotation ? [" is ", print("typeAnnotation")] : "",
];
case "TSNonNullExpression":
return [path.call(print, "expression"), "!"];
return [print("expression"), "!"];
case "TSImportType":
return [
!n.isTypeOf ? "" : "typeof ",
!node.isTypeOf ? "" : "typeof ",
"import(",
path.call(print, n.parameter ? "parameter" : "argument"),
print(node.parameter ? "parameter" : "argument"),
")",
!n.qualifier ? "" : [".", path.call(print, "qualifier")],
!node.qualifier ? "" : [".", print("qualifier")],
printTypeParameters(path, options, print, "typeParameters"),
];
case "TSLiteralType":
return path.call(print, "literal");
return print("literal");
case "TSIndexedAccessType":
return [
path.call(print, "objectType"),
"[",
path.call(print, "indexType"),
"]",
];
return printIndexedAccessType(path, options, print);
case "TSConstructSignatureDeclaration":
case "TSCallSignatureDeclaration":
case "TSConstructorType": {
if (n.type === "TSConstructorType" && n.abstract) {
if (node.type === "TSConstructorType" && node.abstract) {
parts.push("abstract ");
}
if (n.type !== "TSCallSignatureDeclaration") {
if (node.type !== "TSCallSignatureDeclaration") {
parts.push("new ");
}
@@ -315,37 +304,42 @@ function printTypescript(path, options, print) {
)
);
if (n.returnType || n.typeAnnotation) {
const isType = n.type === "TSConstructorType";
if (node.returnType || node.typeAnnotation) {
const isType = node.type === "TSConstructorType";
parts.push(
isType ? " => " : ": ",
path.call(print, "returnType"),
path.call(print, "typeAnnotation")
print("returnType"),
print("typeAnnotation")
);
}
return parts;
}
case "TSTypeOperator":
return [n.operator, " ", path.call(print, "typeAnnotation")];
return [node.operator, " ", print("typeAnnotation")];
case "TSMappedType": {
const shouldBreak = hasNewlineInRange(
options.originalText,
locStart(n),
locEnd(n)
locStart(node),
locEnd(node)
);
return group(
[
"{",
indent([
options.bracketSpacing ? line : softline,
n.readonly
? [getTypeScriptMappedTypeModifier(n.readonly, "readonly"), " "]
node.readonly
? [
getTypeScriptMappedTypeModifier(node.readonly, "readonly"),
" ",
]
: "",
printTypeScriptModifiers(path, options, print),
path.call(print, "typeParameter"),
n.optional ? getTypeScriptMappedTypeModifier(n.optional, "?") : "",
n.typeAnnotation ? ": " : "",
path.call(print, "typeAnnotation"),
print("typeParameter"),
node.optional
? getTypeScriptMappedTypeModifier(node.optional, "?")
: "",
node.typeAnnotation ? ": " : "",
print("typeAnnotation"),
ifBreak(semi),
]),
printDanglingComments(path, options, /* sameIndent */ true),
@@ -357,17 +351,17 @@ function printTypescript(path, options, print) {
}
case "TSMethodSignature": {
parts.push(
n.accessibility ? [n.accessibility, " "] : "",
n.export ? "export " : "",
n.static ? "static " : "",
n.readonly ? "readonly " : "",
node.accessibility ? [node.accessibility, " "] : "",
node.export ? "export " : "",
node.static ? "static " : "",
node.readonly ? "readonly " : "",
// "abstract" and "declare" are supported by only "babel-ts"
// https://github.com/prettier/prettier/issues/9760
n.abstract ? "abstract " : "",
n.declare ? "declare " : "",
n.computed ? "[" : "",
path.call(print, "key"),
n.computed ? "]" : "",
node.abstract ? "abstract " : "",
node.declare ? "declare " : "",
node.computed ? "[" : "",
print("key"),
node.computed ? "]" : "",
printOptionalToken(path)
);
@@ -379,15 +373,13 @@ function printTypescript(path, options, print) {
/* printTypeParams */ true
);
const returnTypePropertyName = n.returnType
const returnTypePropertyName = node.returnType
? "returnType"
: "typeAnnotation";
const returnTypeNode = n[returnTypePropertyName];
const returnTypeDoc = returnTypeNode
? path.call(print, returnTypePropertyName)
: "";
const returnTypeNode = node[returnTypePropertyName];
const returnTypeDoc = returnTypeNode ? print(returnTypePropertyName) : "";
const shouldGroupParameters = shouldGroupFunctionParameters(
n,
node,
returnTypeDoc
);
@@ -400,7 +392,7 @@ function printTypescript(path, options, print) {
return group(parts);
}
case "TSNamespaceExportDeclaration":
parts.push("export as namespace ", path.call(print, "id"));
parts.push("export as namespace ", print("id"));
if (options.semi) {
parts.push(";");
@@ -408,20 +400,20 @@ function printTypescript(path, options, print) {
return group(parts);
case "TSEnumDeclaration":
if (n.declare) {
if (node.declare) {
parts.push("declare ");
}
if (n.modifiers) {
if (node.modifiers) {
parts.push(printTypeScriptModifiers(path, options, print));
}
if (n.const) {
if (node.const) {
parts.push("const ");
}
parts.push("enum ", path.call(print, "id"), " ");
parts.push("enum ", print("id"), " ");
if (n.members.length === 0) {
if (node.members.length === 0) {
parts.push(
group(["{", printDanglingComments(path, options), softline, "}"])
);
@@ -443,21 +435,23 @@ function printTypescript(path, options, print) {
return parts;
case "TSEnumMember":
parts.push(path.call(print, "id"));
if (n.initializer) {
parts.push(" = ", path.call(print, "initializer"));
parts.push(print("id"));
if (node.initializer) {
parts.push(" = ", print("initializer"));
}
return parts;
case "TSImportEqualsDeclaration":
if (n.isExport) {
if (node.isExport) {
parts.push("export ");
}
parts.push(
"import ",
path.call(print, "id"),
" = ",
path.call(print, "moduleReference")
);
parts.push("import ");
if (node.importKind && node.importKind !== "value") {
parts.push(node.importKind, " ");
}
parts.push(print("id"), " = ", print("moduleReference"));
if (options.semi) {
parts.push(";");
@@ -465,31 +459,32 @@ function printTypescript(path, options, print) {
return group(parts);
case "TSExternalModuleReference":
return ["require(", path.call(print, "expression"), ")"];
return ["require(", print("expression"), ")"];
case "TSModuleDeclaration": {
const parent = path.getParentNode();
const isExternalModule = isLiteral(n.id);
const isExternalModule = isLiteral(node.id);
const parentIsDeclaration = parent.type === "TSModuleDeclaration";
const bodyIsDeclaration = n.body && n.body.type === "TSModuleDeclaration";
const bodyIsDeclaration =
node.body && node.body.type === "TSModuleDeclaration";
if (parentIsDeclaration) {
parts.push(".");
} else {
if (n.declare) {
if (node.declare) {
parts.push("declare ");
}
parts.push(printTypeScriptModifiers(path, options, print));
const textBetweenNodeAndItsId = options.originalText.slice(
locStart(n),
locStart(n.id)
locStart(node),
locStart(node.id)
);
// Global declaration looks like this:
// (declare)? global { ... }
const isGlobalDeclaration =
n.id.type === "Identifier" &&
n.id.name === "global" &&
node.id.type === "Identifier" &&
node.id.name === "global" &&
!/namespace|module/.test(textBetweenNodeAndItsId);
if (!isGlobalDeclaration) {
@@ -502,12 +497,12 @@ function printTypescript(path, options, print) {
}
}
parts.push(path.call(print, "id"));
parts.push(print("id"));
if (bodyIsDeclaration) {
parts.push(path.call(print, "body"));
} else if (n.body) {
parts.push(" ", group(path.call(print, "body")));
parts.push(print("body"));
} else if (node.body) {
parts.push(" ", group(print("body")));
} else {
parts.push(semi);
}
@@ -516,13 +511,13 @@ function printTypescript(path, options, print) {
}
// TODO: Temporary auto-generated node type. To remove when typescript-estree has proper support for private fields.
case "TSPrivateIdentifier":
return n.escapedText;
return node.escapedText;
case "TSConditionalType":
return printTernary(path, options, print);
case "TSInferType":
return ["infer", " ", path.call(print, "typeParameter")];
return ["infer", " ", print("typeParameter")];
case "TSIntersectionType":
return printIntersectionType(path, options, print);
case "TSUnionType":
@@ -533,11 +528,11 @@ function printTypescript(path, options, print) {
return printTupleType(path, options, print);
case "TSTypeReference":
return [
path.call(print, "typeName"),
print("typeName"),
printTypeParameters(path, options, print, "typeParameters"),
];
case "TSTypeAnnotation":
return path.call(print, "typeAnnotation");
return print("typeAnnotation");
case "TSEmptyBodyFunctionExpression":
return printMethodInternal(path, options, print);
@@ -547,15 +542,15 @@ function printTypescript(path, options, print) {
case "TSJSDocUnknownType":
return "?";
case "TSJSDocNullableType":
return ["?", path.call(print, "typeAnnotation")];
return ["?", print("typeAnnotation")];
case "TSJSDocNonNullableType":
return ["!", path.call(print, "typeAnnotation")];
return ["!", print("typeAnnotation")];
case "TSJSDocFunctionType":
return [
"function(",
// The parameters could be here, but typescript-estree doesn't convert them anyway (throws an error).
"): ",
path.call(print, "typeAnnotation"),
print("typeAnnotation"),
];
}
}
+5 -9
View File
@@ -9,15 +9,14 @@ function genericPrint(path, options, print) {
const node = path.getValue();
switch (node.type) {
case "JsonRoot":
return [path.call(print, "node"), hardline];
return [print("node"), hardline];
case "ArrayExpression": {
if (node.elements.length === 0) {
return "[]";
}
const printed = path.map(
(elementPath) =>
path.getValue() === null ? "null" : print(elementPath),
() => (path.getValue() === null ? "null" : print()),
"elements"
);
@@ -41,12 +40,9 @@ function genericPrint(path, options, print) {
"}",
];
case "ObjectProperty":
return [path.call(print, "key"), ": ", path.call(print, "value")];
return [print("key"), ": ", print("value")];
case "UnaryExpression":
return [
node.operator === "+" ? "" : node.operator,
path.call(print, "argument"),
];
return [node.operator === "+" ? "" : node.operator, print("argument")];
case "NullLiteral":
return "null";
case "BooleanLiteral":
@@ -63,7 +59,7 @@ function genericPrint(path, options, print) {
}
case "TemplateLiteral":
// There is only one `TemplateElement`
return path.call(print, "quasis", 0);
return print(["quasis", 0]);
case "TemplateElement":
return JSON.stringify(node.value.cooked);
default:
+177 -178
View File
@@ -113,7 +113,7 @@ function genericPrint(path, options, print, args) {
}
const printedDecorators = printDecorators(path, options, print);
// Nodes with decorators can't have parentheses
// Nodes with decorators can't have parentheses and don't need leading semicolons
if (printedDecorators) {
return group([...printedDecorators, printed]);
}
@@ -121,10 +121,10 @@ function genericPrint(path, options, print, args) {
const needsParens = pathNeedsParens(path, options);
if (!needsParens) {
return printed;
return args && args.needsSemi ? [";", printed] : printed;
}
const parts = ["(", printed];
const parts = [args && args.needsSemi ? ";(" : "(", printed];
if (hasFlowShorthandAnnotationComment(node)) {
const [comment] = node.trailingComments;
@@ -138,15 +138,15 @@ function genericPrint(path, options, print, args) {
}
function printPathNoParens(path, options, print, args) {
const n = path.getValue();
const node = path.getValue();
const semi = options.semi ? ";" : "";
if (!n) {
if (!node) {
return "";
}
if (typeof n === "string") {
return n;
if (typeof node === "string") {
return node;
}
for (const printer of [
@@ -166,19 +166,19 @@ function printPathNoParens(path, options, print, args) {
/** @type{Doc[]} */
let parts = [];
switch (n.type) {
switch (node.type) {
case "JsExpressionRoot":
return path.call(print, "node");
return print("node");
case "JsonRoot":
return [path.call(print, "node"), hardline];
return [print("node"), hardline];
case "File":
// Print @babel/parser's InterpreterDirective here so that
// leading comments on the `Program` node get printed after the hashbang.
if (n.program && n.program.interpreter) {
parts.push(path.call(print, "program", "interpreter"));
if (node.program && node.program.interpreter) {
parts.push(print(["program", "interpreter"]));
}
parts.push(path.call(print, "program"));
parts.push(print("program"));
return parts;
@@ -189,8 +189,8 @@ function printPathNoParens(path, options, print, args) {
return "";
case "ExpressionStatement":
// Detect Flow and TypeScript directives
if (n.directive) {
return [printDirective(n.expression, options), semi];
if (node.directive) {
return [printDirective(node.expression, options), semi];
}
if (options.parser === "__vue_event_binding") {
@@ -198,32 +198,32 @@ function printPathNoParens(path, options, print, args) {
if (
parent.type === "Program" &&
parent.body.length === 1 &&
parent.body[0] === n
parent.body[0] === node
) {
return [
path.call(print, "expression"),
isVueEventBindingExpression(n.expression) ? ";" : "",
print("expression"),
isVueEventBindingExpression(node.expression) ? ";" : "",
];
}
}
// Do not append semicolon after the only JSX element in a program
return [
path.call(print, "expression"),
print("expression"),
isTheOnlyJsxElementInMarkdown(options, path) ? "" : semi,
];
// Babel non-standard node. Used for Closure-style type casts. See postprocess.js.
case "ParenthesizedExpression": {
const shouldHug =
!hasComment(n.expression) &&
(n.expression.type === "ObjectExpression" ||
n.expression.type === "ArrayExpression");
!hasComment(node.expression) &&
(node.expression.type === "ObjectExpression" ||
node.expression.type === "ArrayExpression");
if (shouldHug) {
return ["(", path.call(print, "expression"), ")"];
return ["(", print("expression"), ")"];
}
return group([
"(",
indent([softline, path.call(print, "expression")]),
indent([softline, print("expression")]),
softline,
")",
]);
@@ -236,16 +236,16 @@ function printPathNoParens(path, options, print, args) {
case "LogicalExpression":
return printBinaryishExpression(path, options, print);
case "AssignmentPattern":
return [path.call(print, "left"), " = ", path.call(print, "right")];
return [print("left"), " = ", print("right")];
case "OptionalMemberExpression":
case "MemberExpression": {
return printMemberExpression(path, options, print);
}
case "MetaProperty":
return [path.call(print, "meta"), ".", path.call(print, "property")];
return [print("meta"), ".", print("property")];
case "BindExpression":
if (n.object) {
parts.push(path.call(print, "object"));
if (node.object) {
parts.push(print("object"));
}
parts.push(
@@ -257,13 +257,13 @@ function printPathNoParens(path, options, print, args) {
return parts;
case "Identifier": {
return [
n.name,
node.name,
printOptionalToken(path),
printTypeAnnotation(path, options, print),
];
}
case "V8IntrinsicIdentifier":
return ["%", n.name];
return ["%", node.name];
case "SpreadElement":
case "SpreadElementPattern":
case "SpreadProperty":
@@ -272,7 +272,7 @@ function printPathNoParens(path, options, print, args) {
case "ObjectTypeSpreadProperty":
return [
"...",
path.call(print, "argument"),
print("argument"),
printTypeAnnotation(path, options, print),
];
case "FunctionDeclaration":
@@ -291,22 +291,22 @@ function printPathNoParens(path, options, print, args) {
case "YieldExpression":
parts.push("yield");
if (n.delegate) {
if (node.delegate) {
parts.push("*");
}
if (n.argument) {
parts.push(" ", path.call(print, "argument"));
if (node.argument) {
parts.push(" ", print("argument"));
}
return parts;
case "AwaitExpression": {
parts.push("await");
if (n.argument) {
parts.push(" ", path.call(print, "argument"));
if (node.argument) {
parts.push(" ", print("argument"));
const parent = path.getParentNode();
if (
(isCallExpression(parent) && parent.callee === n) ||
(isMemberExpression(parent) && parent.object === n)
(isCallExpression(parent) && parent.callee === node) ||
(isMemberExpression(parent) && parent.object === node)
) {
parts = [indent([softline, ...parts]), softline];
const parentAwaitOrBlock = path.findAncestor(
@@ -338,7 +338,7 @@ function printPathNoParens(path, options, print, args) {
case "ExportDefaultSpecifier":
return printModuleSpecifier(path, options, print);
case "ImportAttribute":
return [path.call(print, "key"), ": ", path.call(print, "value")];
return [print("key"), ": ", print("value")];
case "Import":
return "import";
case "BlockStatement":
@@ -356,13 +356,13 @@ function printPathNoParens(path, options, print, args) {
return printCallExpression(path, options, print);
case "ObjectTypeInternalSlot":
return [
n.static ? "static " : "",
node.static ? "static " : "",
"[[",
path.call(print, "id"),
print("id"),
"]]",
printOptionalToken(path),
n.method ? "" : ": ",
path.call(print, "value"),
node.method ? "" : ": ",
print("value"),
];
case "ObjectExpression":
@@ -373,14 +373,14 @@ function printPathNoParens(path, options, print, args) {
// Babel 6
case "ObjectProperty": // Non-standard AST node type.
case "Property":
if (n.method || n.kind === "get" || n.kind === "set") {
if (node.method || node.kind === "get" || node.kind === "set") {
return printMethod(path, options, print);
}
return printProperty(path, options, print);
case "ObjectMethod":
return printMethod(path, options, print);
case "Decorator":
return ["@", path.call(print, "expression")];
return ["@", print("expression")];
case "ArrayExpression":
case "ArrayPattern":
case "TupleExpression":
@@ -397,9 +397,9 @@ function printPathNoParens(path, options, print, args) {
const parts = [];
path.each((expressionPath, index) => {
if (index === 0) {
parts.push(print(expressionPath));
parts.push(print());
} else {
parts.push(",", indent([line, print(expressionPath)]));
parts.push(",", indent([line, print()]));
}
}, "expressions");
return group(parts);
@@ -411,34 +411,29 @@ function printPathNoParens(path, options, print, args) {
case "Super":
return "super";
case "Directive":
return [path.call(print, "value"), semi]; // Babel 6
return [print("value"), semi]; // Babel 6
case "DirectiveLiteral":
return printDirective(n, options);
return printDirective(node, options);
case "UnaryExpression":
parts.push(n.operator);
parts.push(node.operator);
if (/[a-z]$/.test(n.operator)) {
if (/[a-z]$/.test(node.operator)) {
parts.push(" ");
}
if (hasComment(n.argument)) {
if (hasComment(node.argument)) {
parts.push(
group([
"(",
indent([softline, path.call(print, "argument")]),
softline,
")",
])
group(["(", indent([softline, print("argument")]), softline, ")"])
);
} else {
parts.push(path.call(print, "argument"));
parts.push(print("argument"));
}
return parts;
case "UpdateExpression":
parts.push(path.call(print, "argument"), n.operator);
parts.push(print("argument"), node.operator);
if (n.prefix) {
if (node.prefix) {
parts.reverse();
}
@@ -446,7 +441,7 @@ function printPathNoParens(path, options, print, args) {
case "ConditionalExpression":
return printTernary(path, options, print);
case "VariableDeclaration": {
const printed = path.map((childPath) => print(childPath), "declarations");
const printed = path.map(print, "declarations");
// We generally want to terminate all variable declarations with a
// semicolon, except when they in the () part of for loops.
@@ -457,10 +452,10 @@ function printPathNoParens(path, options, print, args) {
parentNode.type === "ForInStatement" ||
parentNode.type === "ForOfStatement";
const hasValue = n.declarations.some((decl) => decl.init);
const hasValue = node.declarations.some((decl) => decl.init);
let firstVariable;
if (printed.length === 1 && !hasComment(n.declarations[0])) {
if (printed.length === 1 && !hasComment(node.declarations[0])) {
firstVariable = printed[0];
} else if (printed.length > 0) {
// Indent first var to comply with eslint one-var rule
@@ -468,8 +463,8 @@ function printPathNoParens(path, options, print, args) {
}
parts = [
n.declare ? "declare " : "",
n.kind,
node.declare ? "declare " : "",
node.kind,
firstVariable ? [" ", firstVariable] : "",
indent(
printed
@@ -482,7 +477,7 @@ function printPathNoParens(path, options, print, args) {
),
];
if (!(isParentForLoop && parentNode.body !== n)) {
if (!(isParentForLoop && parentNode.body !== node)) {
parts.push(semi);
}
@@ -491,32 +486,32 @@ function printPathNoParens(path, options, print, args) {
case "WithStatement":
return group([
"with (",
path.call(print, "object"),
print("object"),
")",
adjustClause(n.body, path.call(print, "body")),
adjustClause(node.body, print("body")),
]);
case "IfStatement": {
const con = adjustClause(n.consequent, path.call(print, "consequent"));
const con = adjustClause(node.consequent, print("consequent"));
const opening = group([
"if (",
group([indent([softline, path.call(print, "test")]), softline]),
group([indent([softline, print("test")]), softline]),
")",
con,
]);
parts.push(opening);
if (n.alternate) {
if (node.alternate) {
const commentOnOwnLine =
hasComment(
n.consequent,
node.consequent,
CommentCheckFlags.Trailing | CommentCheckFlags.Line
) || needsHardlineAfterDanglingComment(n);
) || needsHardlineAfterDanglingComment(node);
const elseOnSameLine =
n.consequent.type === "BlockStatement" && !commentOnOwnLine;
node.consequent.type === "BlockStatement" && !commentOnOwnLine;
parts.push(elseOnSameLine ? " " : hardline);
if (hasComment(n, CommentCheckFlags.Dangling)) {
if (hasComment(node, CommentCheckFlags.Dangling)) {
parts.push(
printDanglingComments(path, options, true),
commentOnOwnLine ? hardline : " "
@@ -527,9 +522,9 @@ function printPathNoParens(path, options, print, args) {
"else",
group(
adjustClause(
n.alternate,
path.call(print, "alternate"),
n.alternate.type === "IfStatement"
node.alternate,
print("alternate"),
node.alternate.type === "IfStatement"
)
)
);
@@ -538,7 +533,7 @@ function printPathNoParens(path, options, print, args) {
return parts;
}
case "ForStatement": {
const body = adjustClause(n.body, path.call(print, "body"));
const body = adjustClause(node.body, print("body"));
// We want to keep dangling comments above the loop to stay consistent.
// Any comment positioned between the for statement and the parentheses
@@ -550,7 +545,7 @@ function printPathNoParens(path, options, print, args) {
);
const printedComments = dangling ? [dangling, softline] : "";
if (!n.init && !n.test && !n.update) {
if (!node.init && !node.test && !node.update) {
return [printedComments, group(["for (;;)", body])];
}
@@ -561,13 +556,13 @@ function printPathNoParens(path, options, print, args) {
group([
indent([
softline,
path.call(print, "init"),
print("init"),
";",
line,
path.call(print, "test"),
print("test"),
";",
line,
path.call(print, "update"),
print("update"),
]),
softline,
]),
@@ -579,45 +574,45 @@ function printPathNoParens(path, options, print, args) {
case "WhileStatement":
return group([
"while (",
group([indent([softline, path.call(print, "test")]), softline]),
group([indent([softline, print("test")]), softline]),
")",
adjustClause(n.body, path.call(print, "body")),
adjustClause(node.body, print("body")),
]);
case "ForInStatement":
return group([
"for (",
path.call(print, "left"),
print("left"),
" in ",
path.call(print, "right"),
print("right"),
")",
adjustClause(n.body, path.call(print, "body")),
adjustClause(node.body, print("body")),
]);
case "ForOfStatement":
return group([
"for",
n.await ? " await" : "",
node.await ? " await" : "",
" (",
path.call(print, "left"),
print("left"),
" of ",
path.call(print, "right"),
print("right"),
")",
adjustClause(n.body, path.call(print, "body")),
adjustClause(node.body, print("body")),
]);
case "DoWhileStatement": {
const clause = adjustClause(n.body, path.call(print, "body"));
const clause = adjustClause(node.body, print("body"));
const doBody = group(["do", clause]);
parts = [doBody];
if (n.body.type === "BlockStatement") {
if (node.body.type === "BlockStatement") {
parts.push(" ");
} else {
parts.push(hardline);
}
parts.push(
"while (",
group([indent([softline, path.call(print, "test")]), softline]),
group([indent([softline, print("test")]), softline]),
")",
semi
);
@@ -625,12 +620,12 @@ function printPathNoParens(path, options, print, args) {
return parts;
}
case "DoExpression":
return ["do ", path.call(print, "body")];
return ["do ", print("body")];
case "BreakStatement":
parts.push("break");
if (n.label) {
parts.push(" ", path.call(print, "label"));
if (node.label) {
parts.push(" ", print("label"));
}
parts.push(semi);
@@ -639,30 +634,30 @@ function printPathNoParens(path, options, print, args) {
case "ContinueStatement":
parts.push("continue");
if (n.label) {
parts.push(" ", path.call(print, "label"));
if (node.label) {
parts.push(" ", print("label"));
}
parts.push(semi);
return parts;
case "LabeledStatement":
if (n.body.type === "EmptyStatement") {
return [path.call(print, "label"), ":;"];
if (node.body.type === "EmptyStatement") {
return [print("label"), ":;"];
}
return [path.call(print, "label"), ": ", path.call(print, "body")];
return [print("label"), ": ", print("body")];
case "TryStatement":
return [
"try ",
path.call(print, "block"),
n.handler ? [" ", path.call(print, "handler")] : "",
n.finalizer ? [" finally ", path.call(print, "finalizer")] : "",
print("block"),
node.handler ? [" ", print("handler")] : "",
node.finalizer ? [" finally ", print("finalizer")] : "",
];
case "CatchClause":
if (n.param) {
if (node.param) {
const parameterHasComments = hasComment(
n.param,
node.param,
(comment) =>
!isBlockComment(comment) ||
(comment.leading &&
@@ -672,29 +667,29 @@ function printPathNoParens(path, options, print, args) {
backwards: true,
}))
);
const param = path.call(print, "param");
const param = print("param");
return [
"catch ",
parameterHasComments
? ["(", indent([softline, param]), softline, ") "]
: ["(", param, ") "],
path.call(print, "body"),
print("body"),
];
}
return ["catch ", path.call(print, "body")];
return ["catch ", print("body")];
// Note: ignoring n.lexical because it has no printing consequences.
case "SwitchStatement":
return [
group([
"switch (",
indent([softline, path.call(print, "discriminant")]),
indent([softline, print("discriminant")]),
softline,
")",
]),
" {",
n.cases.length > 0
node.cases.length > 0
? indent([
hardline,
join(
@@ -702,7 +697,7 @@ function printPathNoParens(path, options, print, args) {
path.map((casePath, index, cases) => {
const caseNode = casePath.getValue();
return [
casePath.call(print),
print(),
index !== cases.length - 1 &&
isNextLineEmpty(caseNode, options)
? hardline
@@ -716,13 +711,13 @@ function printPathNoParens(path, options, print, args) {
"}",
];
case "SwitchCase": {
if (n.test) {
parts.push("case ", path.call(print, "test"), ":");
if (node.test) {
parts.push("case ", print("test"), ":");
} else {
parts.push("default:");
}
const consequent = n.consequent.filter(
const consequent = node.consequent.filter(
(node) => node.type !== "EmptyStatement"
);
@@ -754,15 +749,11 @@ function printPathNoParens(path, options, print, args) {
case "ClassPrivateProperty":
return printClassProperty(path, options, print);
case "TemplateElement":
return join(literalline, n.value.raw.split(/\r?\n/g));
return join(literalline, node.value.raw.split(/\r?\n/g));
case "TemplateLiteral":
return printTemplateLiteral(path, print, options);
case "TaggedTemplateExpression":
return [
path.call(print, "tag"),
path.call(print, "typeParameters"),
path.call(print, "quasi"),
];
return [print("tag"), print("typeParameters"), print("quasi")];
// These types are unprintable because they serve as abstract
// supertypes for other (printable) types.
case "Node":
@@ -780,7 +771,7 @@ function printPathNoParens(path, options, print, args) {
case "MemberTypeAnnotation": // Flow
case "Type":
/* istanbul ignore next */
throw new Error("unprintable type: " + JSON.stringify(n.type));
throw new Error("unprintable type: " + JSON.stringify(node.type));
case "ExistsTypeAnnotation":
return "*";
case "EmptyTypeAnnotation":
@@ -788,19 +779,19 @@ function printPathNoParens(path, options, print, args) {
case "MixedTypeAnnotation":
return "mixed";
case "ArrayTypeAnnotation":
return [path.call(print, "elementType"), "[]"];
return [print("elementType"), "[]"];
case "BooleanLiteralTypeAnnotation":
return String(n.value);
return String(node.value);
case "EnumDeclaration":
return ["enum ", path.call(print, "id"), " ", path.call(print, "body")];
return ["enum ", print("id"), " ", print("body")];
case "EnumBooleanBody":
case "EnumNumberBody":
case "EnumStringBody":
case "EnumSymbolBody": {
if (n.type === "EnumSymbolBody" || n.explicitType) {
if (node.type === "EnumSymbolBody" || node.explicitType) {
let type = null;
switch (n.type) {
switch (node.type) {
case "EnumBooleanBody":
type = "boolean";
break;
@@ -816,17 +807,17 @@ function printPathNoParens(path, options, print, args) {
}
parts.push("of ", type, " ");
}
if (n.members.length === 0 && !n.hasUnknownMembers) {
if (node.members.length === 0 && !node.hasUnknownMembers) {
parts.push(
group(["{", printDanglingComments(path, options), softline, "}"])
);
} else {
const members =
n.members.length > 0
node.members.length > 0
? [
hardline,
printArrayItems(path, options, "members", print),
n.hasUnknownMembers || shouldPrintComma(options) ? "," : "",
node.hasUnknownMembers || shouldPrintComma(options) ? "," : "",
]
: [];
@@ -835,7 +826,7 @@ function printPathNoParens(path, options, print, args) {
"{",
indent([
...members,
...(n.hasUnknownMembers ? [hardline, "..."] : []),
...(node.hasUnknownMembers ? [hardline, "..."] : []),
]),
printDanglingComments(path, options, /* sameIndent */ true),
hardline,
@@ -849,23 +840,23 @@ function printPathNoParens(path, options, print, args) {
case "EnumNumberMember":
case "EnumStringMember":
return [
path.call(print, "id"),
print("id"),
" = ",
typeof n.init === "object" ? path.call(print, "init") : String(n.init),
typeof node.init === "object" ? print("init") : String(node.init),
];
case "EnumDefaultedMember":
return path.call(print, "id");
return print("id");
case "FunctionTypeParam": {
const name = n.name
? path.call(print, "name")
: path.getParentNode().this === n
const name = node.name
? print("name")
: path.getParentNode().this === node
? "this"
: "";
return [
name,
printOptionalToken(path),
name ? ": " : "",
path.call(print, "typeAnnotation"),
print("typeAnnotation"),
];
}
@@ -874,68 +865,68 @@ function printPathNoParens(path, options, print, args) {
return printInterface(path, options, print);
case "ClassImplements":
case "InterfaceExtends":
return [path.call(print, "id"), path.call(print, "typeParameters")];
return [print("id"), print("typeParameters")];
case "NullableTypeAnnotation":
return ["?", path.call(print, "typeAnnotation")];
return ["?", print("typeAnnotation")];
case "Variance": {
const { kind } = n;
const { kind } = node;
assert.ok(kind === "plus" || kind === "minus");
return kind === "plus" ? "+" : "-";
}
case "ObjectTypeCallProperty":
if (n.static) {
if (node.static) {
parts.push("static ");
}
parts.push(path.call(print, "value"));
parts.push(print("value"));
return parts;
case "ObjectTypeIndexer": {
return [
n.variance ? path.call(print, "variance") : "",
node.variance ? print("variance") : "",
"[",
path.call(print, "id"),
n.id ? ": " : "",
path.call(print, "key"),
print("id"),
node.id ? ": " : "",
print("key"),
"]: ",
path.call(print, "value"),
print("value"),
];
}
case "ObjectTypeProperty": {
let modifier = "";
if (n.proto) {
if (node.proto) {
modifier = "proto ";
} else if (n.static) {
} else if (node.static) {
modifier = "static ";
}
return [
modifier,
isGetterOrSetter(n) ? n.kind + " " : "",
n.variance ? path.call(print, "variance") : "",
isGetterOrSetter(node) ? node.kind + " " : "",
node.variance ? print("variance") : "",
printPropertyKey(path, options, print),
printOptionalToken(path),
isFunctionNotation(n) ? "" : ": ",
path.call(print, "value"),
isFunctionNotation(node) ? "" : ": ",
print("value"),
];
}
case "QualifiedTypeIdentifier":
return [path.call(print, "qualification"), ".", path.call(print, "id")];
return [print("qualification"), ".", print("id")];
case "StringLiteralTypeAnnotation":
return printString(rawText(n), options);
return printString(rawText(node), options);
case "NumberLiteralTypeAnnotation":
assert.strictEqual(typeof n.value, "number");
assert.strictEqual(typeof node.value, "number");
// fall through
case "BigIntLiteralTypeAnnotation":
if (n.extra) {
return printNumber(n.extra.raw);
if (node.extra) {
return printNumber(node.extra.raw);
}
return printNumber(n.raw);
return printNumber(node.raw);
case "TypeCastExpression": {
return [
"(",
path.call(print, "expression"),
print("expression"),
printTypeAnnotation(path, options, print),
")",
];
@@ -946,8 +937,8 @@ function printPathNoParens(path, options, print, args) {
const printed = printTypeParameters(path, options, print, "params");
if (options.parser === "flow") {
const start = locStart(n);
const end = locEnd(n);
const start = locStart(node);
const end = locEnd(node);
const commentStartIndex = options.originalText.lastIndexOf("/*", start);
const commentEndIndex = options.originalText.indexOf("*/", end);
if (commentStartIndex !== -1 && commentEndIndex !== -1) {
@@ -973,7 +964,7 @@ function printPathNoParens(path, options, print, args) {
// be either left alone or desugared into AST types that are fully
// supported by the pretty-printer.
case "DeclaredPredicate":
return ["%checks(", path.call(print, "value"), ")"];
return ["%checks(", print("value"), ")"];
case "AnyTypeAnnotation":
case "TSAnyKeyword":
return "any";
@@ -1005,34 +996,42 @@ function printPathNoParens(path, options, print, args) {
return "this";
case "PrivateIdentifier":
return ["#", path.call(print, "name")];
return ["#", print("name")];
case "PrivateName":
return ["#", path.call(print, "id")];
return ["#", print("id")];
case "InterpreterDirective":
parts.push("#!", n.value, hardline);
parts.push("#!", node.value, hardline);
if (isNextLineEmpty(n, options)) {
if (isNextLineEmpty(node, options)) {
parts.push(hardline);
}
return parts;
case "PipelineBareFunction":
return path.call(print, "callee");
return print("callee");
case "PipelineTopicExpression":
return path.call(print, "expression");
case "PipelinePrimaryTopicReference": {
parts.push("#");
return parts;
}
return print("expression");
case "PipelinePrimaryTopicReference":
return "#";
case "ArgumentPlaceholder":
return "?";
case "ModuleExpression": {
parts.push("module {");
const printed = print("body");
if (printed) {
parts.push(indent([hardline, printed]), hardline);
}
parts.push("}");
return parts;
}
default:
/* istanbul ignore next */
throw new Error("unknown type: " + JSON.stringify(n.type));
throw new Error("unknown type: " + JSON.stringify(node.type));
}
}
+25 -23
View File
@@ -506,34 +506,36 @@ function isUnitTestSetUp(node) {
}
// eg; `describe("some string", (done) => {})`
function isTestCall(n, parent) {
if (n.type !== "CallExpression") {
function isTestCall(node, parent) {
if (node.type !== "CallExpression") {
return false;
}
if (n.arguments.length === 1) {
if (isAngularTestWrapper(n) && parent && isTestCall(parent)) {
return isFunctionOrArrowExpression(n.arguments[0]);
if (node.arguments.length === 1) {
if (isAngularTestWrapper(node) && parent && isTestCall(parent)) {
return isFunctionOrArrowExpression(node.arguments[0]);
}
if (isUnitTestSetUp(n)) {
return isAngularTestWrapper(n.arguments[0]);
if (isUnitTestSetUp(node)) {
return isAngularTestWrapper(node.arguments[0]);
}
} else if (n.arguments.length === 2 || n.arguments.length === 3) {
} else if (node.arguments.length === 2 || node.arguments.length === 3) {
if (
((n.callee.type === "Identifier" && unitTestRe.test(n.callee.name)) ||
isSkipOrOnlyBlock(n)) &&
(isTemplateLiteral(n.arguments[0]) || isStringLiteral(n.arguments[0]))
((node.callee.type === "Identifier" &&
unitTestRe.test(node.callee.name)) ||
isSkipOrOnlyBlock(node)) &&
(isTemplateLiteral(node.arguments[0]) ||
isStringLiteral(node.arguments[0]))
) {
// it("name", () => { ... }, 2500)
if (n.arguments[2] && !isNumericLiteral(n.arguments[2])) {
if (node.arguments[2] && !isNumericLiteral(node.arguments[2])) {
return false;
}
return (
(n.arguments.length === 2
? isFunctionOrArrowExpression(n.arguments[1])
: isFunctionOrArrowExpressionWithBody(n.arguments[1]) &&
getFunctionParameters(n.arguments[1]).length <= 1) ||
isAngularTestWrapper(n.arguments[1])
(node.arguments.length === 2
? isFunctionOrArrowExpression(node.arguments[1])
: isFunctionOrArrowExpressionWithBody(node.arguments[1]) &&
getFunctionParameters(node.arguments[1]).length <= 1) ||
isAngularTestWrapper(node.arguments[1])
);
}
}
@@ -783,16 +785,16 @@ function templateLiteralHasNewLines(template) {
}
/**
* @param {TemplateLiteral | TaggedTemplateExpression} n
* @param {TemplateLiteral | TaggedTemplateExpression} node
* @param {string} text
* @returns {boolean}
*/
function isTemplateOnItsOwnLine(n, text) {
function isTemplateOnItsOwnLine(node, text) {
return (
((n.type === "TemplateLiteral" && templateLiteralHasNewLines(n)) ||
(n.type === "TaggedTemplateExpression" &&
templateLiteralHasNewLines(n.quasi))) &&
!hasNewline(text, locStart(n), { backwards: true })
((node.type === "TemplateLiteral" && templateLiteralHasNewLines(node)) ||
(node.type === "TaggedTemplateExpression" &&
templateLiteralHasNewLines(node.quasi))) &&
!hasNewline(text, locStart(node), { backwards: true })
);
}
+2 -1
View File
@@ -1,5 +1,6 @@
"use strict";
const getLast = require("../utils/get-last");
const { getOrderedListItemInfo, mapAst, splitText } = require("./utils");
// 0x0 ~ 0x10ffff
@@ -78,7 +79,7 @@ function mergeChildren(ast, shouldMerge, mergeNode) {
return node;
}
const children = node.children.reduce((current, child) => {
const lastChild = current[current.length - 1];
const lastChild = getLast(current);
if (lastChild && shouldMerge(lastChild, child)) {
current.splice(-1, 1, mergeNode(lastChild, child));
} else {
+7 -9
View File
@@ -410,9 +410,7 @@ function genericPrint(path, options, print) {
" ".repeat(4),
printChildren(path, options, print, {
processor: (childPath, index) =>
index === 0
? group([softline, childPath.call(print)])
: childPath.call(print),
index === 0 ? group([softline, print()]) : print(),
})
),
nextNode && nextNode.type === "footnoteDefinition"
@@ -469,13 +467,13 @@ function printListItem(path, options, print, listPrefix) {
printChildren(path, options, print, {
processor: (childPath, index) => {
if (index === 0 && childPath.getValue().type !== "list") {
return align(" ".repeat(prefix.length), childPath.call(print));
return align(" ".repeat(prefix.length), print());
}
const alignment = " ".repeat(
clamp(options.tabWidth - listPrefix.length, 0, 3) // 4+ will cause indented code block
);
return [alignment, align(alignment, childPath.call(print))];
return [alignment, align(alignment, print())];
},
}),
];
@@ -565,7 +563,7 @@ function printTable(path, options, print) {
const contents = path.map(
(rowPath) =>
rowPath.map((cellPath, columnIndex) => {
const text = printDocToString(cellPath.call(print), options).formatted;
const text = printDocToString(print(), options).formatted;
const width = getStringWidth(text);
columnMaxWidths[columnIndex] = Math.max(
columnMaxWidths[columnIndex] || 3, // minimum width = 3 (---, :--, :-:, --:)
@@ -691,14 +689,14 @@ function printRoot(path, options, print) {
}
}
return childPath.call(print);
return print();
},
});
}
function printChildren(path, options, print, events = {}) {
const { postprocessor } = events;
const processor = events.processor || ((childPath) => childPath.call(print));
const processor = events.processor || (() => print());
const node = path.getValue();
const parts = [];
@@ -752,7 +750,7 @@ function printChildren(path, options, print, events = {}) {
function getLastDescendantNode(node) {
let current = node;
while (isNonEmptyArray(current.children)) {
current = current.children[current.children.length - 1];
current = getLast(current.children);
}
return current;
}
+1 -1
View File
@@ -41,7 +41,7 @@ function printBlock(path, print, options) {
}
if (hasIndicatorComment(node)) {
parts.push(" ", path.call(print, "indicatorComment"));
parts.push(" ", print("indicatorComment"));
}
const lineContents = getBlockValueLineContents(node, {
@@ -43,7 +43,7 @@ function printChildren(path, print, options) {
const node = path.getValue();
const parts = path.map(
(childPath, index) => [
print(childPath),
print(),
index === node.children.length - 1
? ""
: [
+2 -2
View File
@@ -26,7 +26,7 @@ function printMappingItem(node, parentNode, path, print, options) {
return ": ";
}
const printedKey = path.call(print, "key");
const printedKey = print("key");
const spaceBeforeColon = needsSpaceInFrontOfMappingValue(node) ? " " : "";
if (isEmptyMappingValue) {
@@ -46,7 +46,7 @@ function printMappingItem(node, parentNode, path, print, options) {
return ["? ", alignWithSpaces(2, printedKey)];
}
const printedValue = path.call(print, "value");
const printedValue = print("value");
if (isEmptyMappingKey) {
return [": ", alignWithSpaces(2, printedValue)];
}
+2 -2
View File
@@ -44,8 +44,8 @@ function shouldPrintEndComments(node) {
);
}
function alignWithSpaces(n, doc) {
return align(" ".repeat(n), doc);
function alignWithSpaces(width, doc) {
return align(" ".repeat(width), doc);
}
module.exports = {
+13 -18
View File
@@ -55,13 +55,13 @@ function genericPrint(path, options, print) {
const { tag, anchor } = node;
if (tag) {
parts.push(path.call(print, "tag"));
parts.push(print("tag"));
}
if (tag && anchor) {
parts.push(" ");
}
if (anchor) {
parts.push(path.call(print, "anchor"));
parts.push(print("anchor"));
}
/** @type {Doc} */
@@ -120,7 +120,7 @@ function genericPrint(path, options, print) {
isInlineNode(node)
? ""
: breakParent,
path.call(print, "trailingComment"),
print("trailingComment"),
])
);
}
@@ -140,7 +140,7 @@ function genericPrint(path, options, print) {
)
? hardline
: "",
print(path),
print(),
],
"endComments"
)
@@ -163,11 +163,11 @@ function printNode(node, parentNode, path, options, print) {
if (index !== 0) {
parts.push(hardline);
}
parts.push(print(childPath));
parts.push(print());
if (shouldPrintDocumentEndMarker(document, nextDocument)) {
parts.push(hardline, "...");
if (hasTrailingComment(document)) {
parts.push(" ", path.call(print, "trailingComment"));
parts.push(" ", print("trailingComment"));
}
} else if (nextDocument && !hasTrailingComment(nextDocument.head)) {
parts.push(hardline, "---");
@@ -195,18 +195,18 @@ function printNode(node, parentNode, path, options, print) {
) === "head"
) {
if (node.head.children.length > 0 || node.head.endComments.length > 0) {
parts.push(path.call(print, "head"));
parts.push(print("head"));
}
if (hasTrailingComment(node.head)) {
parts.push(["---", " ", path.call(print, "head", "trailingComment")]);
parts.push(["---", " ", print(["head", "trailingComment"])]);
} else {
parts.push("---");
}
}
if (shouldPrintDocumentBody(node)) {
parts.push(path.call(print, "body"));
parts.push(print("body"));
}
return join(hardline, parts);
@@ -325,19 +325,14 @@ function printNode(node, parentNode, path, options, print) {
case "blockLiteral": {
return printBlock(path, print, options);
}
case "mapping":
case "sequence":
return join(hardline, path.map(print, "children"));
case "sequenceItem":
return [
"- ",
alignWithSpaces(2, !node.content ? "" : path.call(print, "content")),
];
return ["- ", alignWithSpaces(2, !node.content ? "" : print("content"))];
case "mappingKey":
return !node.content ? "" : path.call(print, "content");
case "mappingValue":
return !node.content ? "" : path.call(print, "content");
case "mapping":
return join(hardline, path.map(print, "children"));
return !node.content ? "" : print("content");
case "mappingItem":
case "flowMappingItem": {
return printMappingItem(node, parentNode, path, print, options);
@@ -347,7 +342,7 @@ function printNode(node, parentNode, path, options, print) {
case "flowSequence":
return printFlowSequence(path, print, options);
case "flowSequenceItem":
return path.call(print, "content");
return print("content");
// istanbul ignore next
default:
throw new Error(`Unexpected node type ${node.type}`);
+68 -56
View File
@@ -1,6 +1,5 @@
"use strict";
const assert = require("assert");
const AstPath = require("../common/ast-path");
const {
builders: { hardline, addAlignmentToDoc },
@@ -16,14 +15,14 @@ const multiparser = require("./multiparser");
* This is done by descending down the AST recursively. The recursion
* involves two functions that call each other:
*
* 1. printGenerically(), which is defined as an inner function here.
* 1. mainPrint(), which is defined as an inner function here.
* It basically takes care of node caching.
* 2. callPluginPrintFunction(), which checks for some options, and
* ultimately calls the print() function provided by the plugin.
*
* The plugin function will call printGenerically() again for child nodes
* of the current node, which will do its housekeeping, then call the
* plugin function again, and so on.
* The plugin function will call mainPrint() again for child nodes
* of the current node. mainPrint() will do its housekeeping, then call
* the plugin function again, and so on.
*
* All the while, these functions pass a "path" variable around, which
* is a stack-like data structure (AstPath) that maintains the current
@@ -38,44 +37,50 @@ function printAstToDoc(ast, options, alignmentSize = 0) {
}
const cache = new Map();
const path = new AstPath(ast);
function printGenerically(path, args) {
const node = path.getValue();
let doc = mainPrint();
const shouldCache = node && typeof node === "object" && args === undefined;
if (shouldCache && cache.has(node)) {
return cache.get(node);
}
let doc = callPluginPrintFunction(path, options, printGenerically, args);
// We let JSXElement print its comments itself because it adds () around
// UnionTypeAnnotation has to align the child without the comments
if (
!printer.willPrintOwnComments ||
!printer.willPrintOwnComments(path, options)
) {
// printComments will call the plugin print function and check for
// comments to print
doc = printComments(path, doc, options, args && args.needsSemi);
}
if (shouldCache) {
cache.set(node, doc);
}
return doc;
}
let doc = printGenerically(new AstPath(ast));
if (alignmentSize > 0) {
// Add a hardline to make the indents take effect
// It should be removed in index.js format()
doc = addAlignmentToDoc([hardline, doc], alignmentSize, options.tabWidth);
}
propagateBreaks(doc);
return doc;
function mainPrint(selector, args) {
if (selector === undefined || selector === path) {
return mainPrintInternal(args);
}
if (Array.isArray(selector)) {
return path.call(() => mainPrintInternal(args), ...selector);
}
return path.call(() => mainPrintInternal(args), selector);
}
function mainPrintInternal(args) {
const value = path.getValue();
const shouldCache =
value && typeof value === "object" && args === undefined;
if (shouldCache && cache.has(value)) {
return cache.get(value);
}
const doc = callPluginPrintFunction(path, options, mainPrint, args);
if (shouldCache) {
cache.set(value, doc);
}
return doc;
}
}
function printPrettierIgnoredNode(node, options) {
@@ -99,38 +104,45 @@ function printPrettierIgnoredNode(node, options) {
}
function callPluginPrintFunction(path, options, printPath, args) {
assert.ok(path instanceof AstPath);
const node = path.getValue();
const { printer } = options;
let doc;
// Escape hatch
if (printer.hasPrettierIgnore && printer.hasPrettierIgnore(path)) {
return printPrettierIgnoredNode(node, options);
}
doc = printPrettierIgnoredNode(node, options);
} else {
if (node) {
try {
// Potentially switch to a different parser
doc = multiparser.printSubtree(path, printPath, options, printAstToDoc);
} catch (error) {
/* istanbul ignore if */
if (process.env.PRETTIER_DEBUG) {
throw error;
}
// Continue with current parser
}
}
if (node) {
try {
// Potentially switch to a different parser
const sub = multiparser.printSubtree(
path,
printPath,
options,
printAstToDoc
);
if (sub) {
return sub;
}
} catch (error) {
/* istanbul ignore if */
if (process.env.PRETTIER_DEBUG) {
throw error;
}
// Continue with current parser
if (!doc) {
doc = printer.print(path, options, printPath, args);
}
}
return printer.print(path, options, printPath, args);
// We let JSXElement print its comments itself because it adds () around
// UnionTypeAnnotation has to align the child without the comments
if (
!printer.willPrintOwnComments ||
!printer.willPrintOwnComments(path, options)
) {
// printComments will call the plugin print function and check for
// comments to print
doc = printComments(path, doc, options);
}
return doc;
}
module.exports = printAstToDoc;
+28 -22
View File
@@ -52,12 +52,12 @@ function getSortedChildNodes(node, options, resultArray) {
(typeof node === "object" &&
Object.entries(node)
.filter(
([n]) =>
n !== "enclosingNode" &&
n !== "precedingNode" &&
n !== "followingNode" &&
n !== "tokens" &&
n !== "comments"
([key]) =>
key !== "enclosingNode" &&
key !== "precedingNode" &&
key !== "followingNode" &&
key !== "tokens" &&
key !== "comments"
)
.map(([, value]) => value));
@@ -540,23 +540,18 @@ function printDanglingComments(path, options, sameIndent, filter) {
return indent([hardline, join(hardline, parts)]);
}
function prependCursorPlaceholder(path, options, printed) {
if (path.getNode() === options.cursorNode && path.getValue()) {
return [cursor, printed, cursor];
}
return printed;
}
function printComments(path, printed, options, needsSemi) {
function printCommentsSeparately(path, options) {
const value = path.getValue();
const comments = value && value.comments;
const hasComments = isNonEmptyArray(value && value.comments);
const isCursorNode = Boolean(value && value === options.cursorNode);
if (!isNonEmptyArray(comments)) {
return prependCursorPlaceholder(path, options, printed);
if (!hasComments) {
const maybeCursor = isCursorNode ? cursor : "";
return { leading: maybeCursor, trailing: maybeCursor };
}
const leadingParts = [];
const trailingParts = [needsSemi ? ";" : "", printed];
const trailingParts = [];
path.each((commentPath) => {
const comment = commentPath.getValue();
@@ -583,10 +578,20 @@ function printComments(path, printed, options, needsSemi) {
}
}, "comments");
return prependCursorPlaceholder(path, options, [
...leadingParts,
...trailingParts,
]);
if (isCursorNode) {
leadingParts.unshift(cursor);
trailingParts.push(cursor);
}
return { leading: leadingParts, trailing: trailingParts };
}
function printComments(path, doc, options) {
const { leading, trailing } = printCommentsSeparately(path, options);
if (!leading && !trailing) {
return doc;
}
return [leading, doc, trailing];
}
function ensureAllCommentsPrinted(astComments) {
@@ -609,6 +614,7 @@ function ensureAllCommentsPrinted(astComments) {
module.exports = {
attach,
printComments,
printCommentsSeparately,
printDanglingComments,
getSortedChildNodes,
ensureAllCommentsPrinted,
+1 -5
View File
@@ -146,11 +146,7 @@ const options = {
{ value: "mdx", since: "1.15.0", description: "MDX" },
{ value: "vue", since: "1.10.0", description: "Vue" },
{ value: "yaml", since: "1.14.0", description: "YAML" },
{
value: "glimmer",
since: null,
description: "Handlebars",
},
{ value: "glimmer", since: "2.3.0", description: "Ember / Handlebars" },
{ value: "html", since: "1.15.0", description: "HTML" },
{ value: "angular", since: "1.15.0", description: "Angular" },
{
+3 -4
View File
@@ -4,6 +4,7 @@ const vnopts = require("vnopts");
const leven = require("leven");
const chalk = require("chalk");
const flat = require("lodash/flatten");
const getLast = require("../utils/get-last");
const cliDescriptor = {
key: (key) => (key.length === 1 ? `-${key}` : `--${key}`),
@@ -21,7 +22,7 @@ const cliDescriptor = {
class FlagSchema extends vnopts.ChoiceSchema {
constructor({ name, flags }) {
super({ name, choices: flags });
this._flags = flags.slice().sort();
this._flags = [...flags].sort();
}
preprocess(value, utils) {
if (
@@ -196,9 +197,7 @@ function optionInfoToSchema(optionInfo, { isCLI, optionInfos }) {
const originalPreprocess = parameters.preprocess || ((x) => x);
parameters.preprocess = (value, schema, utils) =>
schema.preprocess(
originalPreprocess(
Array.isArray(value) ? value[value.length - 1] : value
),
originalPreprocess(Array.isArray(value) ? getLast(value) : value),
utils
);
}
+75 -30
View File
@@ -3,7 +3,41 @@
const assert = require("assert");
const comments = require("./comments");
function findSiblingAncestors(startNodeAndParents, endNodeAndParents, opts) {
const isJsonParser = ({ parser }) =>
parser === "json" || parser === "json5" || parser === "json-stringify";
function findCommonAncestor(startNodeAndParents, endNodeAndParents) {
const startNodeAndAncestors = [
startNodeAndParents.node,
...startNodeAndParents.parentNodes,
];
const endNodeAndAncestors = new Set([
endNodeAndParents.node,
...endNodeAndParents.parentNodes,
]);
return startNodeAndAncestors.find(
(node) => jsonSourceElements.has(node.type) && endNodeAndAncestors.has(node)
);
}
function dropRootParents(parents) {
let lastParentIndex = parents.length - 1;
for (;;) {
const parent = parents[lastParentIndex];
if (parent && (parent.type === "Program" || parent.type === "File")) {
lastParentIndex--;
} else {
break;
}
}
return parents.slice(0, lastParentIndex + 1);
}
function findSiblingAncestors(
startNodeAndParents,
endNodeAndParents,
{ locStart, locEnd }
) {
let resultStartNode = startNodeAndParents.node;
let resultEndNode = endNodeAndParents.node;
@@ -14,24 +48,18 @@ function findSiblingAncestors(startNodeAndParents, endNodeAndParents, opts) {
};
}
for (const endParent of endNodeAndParents.parentNodes) {
if (
endParent.type !== "Program" &&
endParent.type !== "File" &&
opts.locStart(endParent) >= opts.locStart(startNodeAndParents.node)
) {
const startNodeStart = locStart(startNodeAndParents.node);
for (const endParent of dropRootParents(endNodeAndParents.parentNodes)) {
if (locStart(endParent) >= startNodeStart) {
resultEndNode = endParent;
} else {
break;
}
}
for (const startParent of startNodeAndParents.parentNodes) {
if (
startParent.type !== "Program" &&
startParent.type !== "File" &&
opts.locEnd(startParent) <= opts.locEnd(endNodeAndParents.node)
) {
const endNodeEnd = locEnd(endNodeAndParents.node);
for (const startParent of dropRootParents(startNodeAndParents.parentNodes)) {
if (locEnd(startParent) <= endNodeEnd) {
resultStartNode = startParent;
} else {
break;
@@ -79,7 +107,7 @@ function findNodeAtOffset(
}
}
if (!predicate || predicate(node)) {
if (!predicate || predicate(node, parentNodes[0])) {
return {
node,
parentNodes,
@@ -88,15 +116,17 @@ function findNodeAtOffset(
}
// See https://www.ecma-international.org/ecma-262/5.1/#sec-A.5
function isJsSourceElement(type) {
function isJsSourceElement(type, parentType) {
return (
type === "Directive" ||
type === "TypeAlias" ||
type === "TSExportAssignment" ||
type.startsWith("Declare") ||
type.startsWith("TSDeclare") ||
type.endsWith("Statement") ||
type.endsWith("Declaration")
parentType !== "DeclareExportDeclaration" &&
type !== "TypeParameterDeclaration" &&
(type === "Directive" ||
type === "TypeAlias" ||
type === "TSExportAssignment" ||
type.startsWith("Declare") ||
type.startsWith("TSDeclare") ||
type.endsWith("Statement") ||
type.endsWith("Declaration"))
);
}
@@ -107,6 +137,8 @@ const jsonSourceElements = new Set([
"NumericLiteral",
"BooleanLiteral",
"NullLiteral",
"UnaryExpression",
"TemplateLiteral",
]);
const graphqlSourceElements = new Set([
"OperationDefinition",
@@ -126,7 +158,7 @@ const graphqlSourceElements = new Set([
"UnionTypeDefinition",
"ScalarTypeDefinition",
]);
function isSourceElement(opts, node) {
function isSourceElement(opts, node, parentNode) {
/* istanbul ignore next */
if (!node) {
return false;
@@ -139,8 +171,10 @@ function isSourceElement(opts, node) {
case "typescript":
case "espree":
case "meriyah":
return isJsSourceElement(node.type);
return isJsSourceElement(node.type, parentNode && parentNode.type);
case "json":
case "json5":
case "json-stringify":
return jsonSourceElements.has(node.type);
case "graphql":
return graphqlSourceElements.has(node.kind);
@@ -170,7 +204,7 @@ function calculateRange(text, opts, ast) {
ast,
start,
opts,
(node) => isSourceElement(opts, node),
(node, parentNode) => isSourceElement(opts, node, parentNode),
[],
"rangeStart"
);
@@ -193,11 +227,22 @@ function calculateRange(text, opts, ast) {
};
}
const { startNode, endNode } = findSiblingAncestors(
startNodeAndParents,
endNodeAndParents,
opts
);
let startNode;
let endNode;
if (isJsonParser(opts)) {
const commonAncestor = findCommonAncestor(
startNodeAndParents,
endNodeAndParents
);
startNode = commonAncestor;
endNode = commonAncestor;
} else {
({ startNode, endNode } = findSiblingAncestors(
startNodeAndParents,
endNodeAndParents,
opts
));
}
return {
rangeStart: Math.min(locStart(startNode), locStart(endNode)),
+3 -1
View File
@@ -1,3 +1,5 @@
"use strict";
module.exports = (arr) => arr[arr.length - 1];
const getLast = (arr) => arr[arr.length - 1];
module.exports = getLast;
Loaded 100 of 245 files, more files were not shown because too many files have changed in this diff. Show more