Merge branch 'main' into next
# Conflicts: # docs/browser.md # package.json # scripts/release/yarn.lock # scripts/vendors/vendor-meta.json # scripts/vendors/vendors.mjs # src/cli/expand-patterns.js # src/cli/format.js # src/cli/utils.js # src/language-js/index.js # src/language-js/parse/postprocess/index.js # src/language-js/parse/postprocess/typescript.js # tests/format/misc/errors/invalid/jsfmt.spec.js # tests/integration/__tests__/__snapshots__/support-info.js.snap # website/playground/sidebar/SidebarOptions.js # yarn.lock
This commit is contained in:
commit
0e0f879c1a
68 files changed
+2789
-1286
No files matched your search
@@ -5,6 +5,10 @@
|
||||
# See https://git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revs-fileltfilegt
|
||||
|
||||
# Prettier bump after release
|
||||
# 2.7.1
|
||||
1f9baef429df2516ff8eb835fd8c020b5e854a5f
|
||||
# 2.7.0
|
||||
59ec4f2ef4aef37c10a265aa7fc568c596fb4427
|
||||
# 2.6.2
|
||||
e2d9e9139d34043c8e6c45cda2777de013340e2e
|
||||
# 2.6.1
|
||||
|
||||
@@ -26,7 +26,7 @@ Don't fill the form below manually! Let a program create a report for you:
|
||||
|
||||
-->
|
||||
|
||||
**Prettier 2.6.2**
|
||||
**Prettier 2.7.1**
|
||||
[Playground link](https://prettier.io/playground/#.....)
|
||||
|
||||
```sh
|
||||
|
||||
@@ -20,7 +20,7 @@ BEFORE SUBMITTING AN ISSUE:
|
||||
|
||||
**Environments:**
|
||||
|
||||
- Prettier Version: 2.6.2
|
||||
- Prettier Version: 2.7.1
|
||||
- Running Prettier via: <!-- CLI, Node.js API, Browser API, etc. -->
|
||||
- Runtime: <!-- Node.js v14, Chrome v83, etc. -->
|
||||
- Operating System: <!-- Windows, Linux, macOS, etc. -->
|
||||
|
||||
@@ -1,3 +1,48 @@
|
||||
# 2.7.1
|
||||
|
||||
[diff](https://github.com/prettier/prettier/compare/2.7.0...2.7.1)
|
||||
|
||||
#### Keep useful empty lines in description ([#13013](https://github.com/prettier/prettier/pull/13013) by [@chimurai](https://github.com/chimurai))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```graphql
|
||||
# Input
|
||||
"""
|
||||
First line
|
||||
|
||||
Second Line
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
# Prettier 2.7.0
|
||||
"""
|
||||
First line
|
||||
Second Line
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
|
||||
# Prettier 2.7.1
|
||||
"""
|
||||
First line
|
||||
|
||||
Second Line
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
```
|
||||
|
||||
# 2.7.0
|
||||
|
||||
[diff](https://github.com/prettier/prettier/compare/2.6.2...2.7.0)
|
||||
|
||||
🔗 [Release Notes](https://prettier.io/blog/2022/06/14/2.7.0.html)
|
||||
|
||||
# 2.6.2
|
||||
|
||||
[diff](https://github.com/prettier/prettier/compare/2.6.1...2.6.2)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#### Print the number of files need change (#12561 by @Harry-Hopkinson)
|
||||
|
||||
```console
|
||||
# Prettier stable
|
||||
$ prettier src --check
|
||||
Checking formatting...
|
||||
[warn] src/fileA.js
|
||||
[warn] Code style issues found in the above file(s). Forgot to run Prettier?
|
||||
|
||||
# Prettier main
|
||||
$ prettier src --check
|
||||
Checking formatting...
|
||||
[warn] src/fileA.js
|
||||
[warn] src/fileB.js
|
||||
[warn] Code style issues found in 2 files. Forgot to run Prettier?
|
||||
|
||||
$ prettier src --check
|
||||
Checking formatting...
|
||||
[warn] src/fileA.js
|
||||
[warn] Code style issues found in the above file. Forgot to run Prettier?
|
||||
```
|
||||
@@ -1,3 +0,0 @@
|
||||
#### Infer parser for `.importmap` files (#12603 by @fisker)
|
||||
|
||||
Format [`.importmap`](https://github.com/WICG/import-maps#import-map-processing) files as a JSON files.
|
||||
@@ -1,6 +0,0 @@
|
||||
#### Simplify performance test (#12682, #12698 by @fisker)
|
||||
|
||||
When `--debug-benchmark` or `--debug-repeat` is passed:
|
||||
|
||||
1. The CLI skips print code to the screen or write file
|
||||
1. Set log level to `debug` automatically
|
||||
@@ -1,17 +0,0 @@
|
||||
#### Add support for printing SchemaExtension nodes (#12519 by @trevor-scheer)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```graphql
|
||||
# Input
|
||||
extend schema { subscription: Subscription }
|
||||
extend schema @directive
|
||||
|
||||
# Prettier stable
|
||||
N/A - throws error
|
||||
|
||||
# Prettier main
|
||||
extend schema {
|
||||
subscription: Subscription
|
||||
}
|
||||
extend schema @directive
|
||||
```
|
||||
@@ -1,59 +0,0 @@
|
||||
#### Fix single line and empty description formatting (#12608 by @chimurai, @fisker)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```graphql
|
||||
# Input
|
||||
""" Customer """
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
""""""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
# Prettier 2.6.2
|
||||
"""
|
||||
Customer
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
# Prettier 2.6.2 (second format)
|
||||
"""
|
||||
Customer
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
# Prettier main
|
||||
"""
|
||||
Customer
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
"""
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
```
|
||||
@@ -1,32 +0,0 @@
|
||||
#### Support Speculation Rules API formatting in HTML (#12882 by @sosukesuzuki)
|
||||
|
||||
Please read https://web.dev/speculative-prerendering/ for about Speculation Rules API.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```html
|
||||
<!-- Input -->
|
||||
<script type="speculationrules">
|
||||
{
|
||||
"prerender": [
|
||||
{"source": "list", "urls": ["https://a.test/foo"]}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<!-- Prettier stable -->
|
||||
<script type="speculationrules">
|
||||
{
|
||||
"prerender": [
|
||||
{"source": "list", "urls": ["https://a.test/foo"]}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Prettier main -->
|
||||
<script type="speculationrules">
|
||||
{
|
||||
"prerender": [{ "source": "list", "urls": ["https://a.test/foo"] }]
|
||||
}
|
||||
</script>
|
||||
```
|
||||
@@ -1,33 +0,0 @@
|
||||
#### Preserve blank line between export specifiers (#12746 by @sosukesuzuki)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
// Input
|
||||
export {
|
||||
// a
|
||||
foo1,
|
||||
|
||||
// b
|
||||
bar1,
|
||||
baz1,
|
||||
} from "mod";
|
||||
|
||||
// Prettier stable
|
||||
export {
|
||||
// a
|
||||
foo1,
|
||||
// b
|
||||
bar1,
|
||||
baz1,
|
||||
} from "mod";
|
||||
|
||||
// Prettier main
|
||||
export {
|
||||
// a
|
||||
foo1,
|
||||
|
||||
// b
|
||||
bar1,
|
||||
baz1,
|
||||
} from "mod";
|
||||
```
|
||||
@@ -1,77 +0,0 @@
|
||||
#### Make more callee patterns recognized as "test call callee". (#12779 by @HosokawaR)
|
||||
|
||||
Supports test calls like [Playwright `test.describe`](https://playwright.dev/docs/api/class-test#test-describe).
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
// Input
|
||||
test.step("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe.only("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe.parallel("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe.parallel.only("does something really long and complicated so I have to write a very long name for the testThis is a very", () => {});
|
||||
|
||||
test.describe.serial("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe.serial.only("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
// Prettier stable
|
||||
test.step(
|
||||
"does something really long and complicated so I have to write a very long name for the test",
|
||||
() => {}
|
||||
);
|
||||
|
||||
test.describe(
|
||||
"does something really long and complicated so I have to write a very long name for the test",
|
||||
() => {}
|
||||
);
|
||||
|
||||
test.describe.only(
|
||||
"does something really long and complicated so I have to write a very long name for the test",
|
||||
() => {}
|
||||
);
|
||||
|
||||
test.describe.parallel(
|
||||
"does something really long and complicated so I have to write a very long name for the test",
|
||||
() => {}
|
||||
);
|
||||
|
||||
test.describe.parallel.only(
|
||||
"does something really long and complicated so I have to write a very long name for the testThis is a very",
|
||||
() => {}
|
||||
);
|
||||
|
||||
test.describe.serial(
|
||||
"does something really long and complicated so I have to write a very long name for the test",
|
||||
() => {}
|
||||
);
|
||||
|
||||
test.describe.serial.only(
|
||||
"does something really long and complicated so I have to write a very long name for the test",
|
||||
() => {}
|
||||
);
|
||||
|
||||
// Prettier main
|
||||
test.step("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe
|
||||
.only("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe
|
||||
.parallel("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe.parallel
|
||||
.only("does something really long and complicated so I have to write a very long name for the testThis is a very", () => {});
|
||||
|
||||
test.describe
|
||||
.serial("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe.serial
|
||||
.only("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
```
|
||||
@@ -1,49 +0,0 @@
|
||||
#### Fix comment formats in (#12860 by @HosokawaR)
|
||||
|
||||
This change fixes comments format in `exports` to algin with the comment format in `import`
|
||||
|
||||
Although this change does not affect the comments format in `import`, follows change log contains examples of comments in `import` for reference.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
// Input
|
||||
export {
|
||||
foo,
|
||||
|
||||
bar as // comment
|
||||
baz,
|
||||
}
|
||||
|
||||
import {
|
||||
foo,
|
||||
|
||||
bar as // comment
|
||||
baz,
|
||||
} from 'foo'
|
||||
|
||||
// Prettier stable
|
||||
export {
|
||||
foo,
|
||||
bar as baz, // comment
|
||||
};
|
||||
|
||||
import {
|
||||
foo,
|
||||
// comment
|
||||
bar as baz,
|
||||
} from "foo";
|
||||
|
||||
// Prettier main
|
||||
export {
|
||||
foo,
|
||||
// comment
|
||||
bar as baz,
|
||||
};
|
||||
|
||||
import {
|
||||
foo,
|
||||
// comment
|
||||
bar as baz,
|
||||
} from "foo";
|
||||
|
||||
```
|
||||
@@ -1,13 +0,0 @@
|
||||
#### Print `as` instead of `:` for `babel-ts` parser (#12706 by @HosokawaR)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```tsx
|
||||
// Input
|
||||
[x as any] = x;
|
||||
|
||||
// Prettier stable
|
||||
[x: any] = x;
|
||||
|
||||
// Prettier main
|
||||
[x as any] = x;
|
||||
```
|
||||
@@ -1,37 +0,0 @@
|
||||
#### [HIGHLIGHT]Support TypeScript 4.7 (#12896, #12897, #12898, #12900, #12921, #12924, #12959 by @sosukesuzuki)
|
||||
|
||||
Support [TypeScript 4.7](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7) new features!
|
||||
|
||||
##### [Instantiation Expressions](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#instantiation-expressions)
|
||||
|
||||
```ts
|
||||
interface Box<T> {
|
||||
value: T;
|
||||
}
|
||||
function makeBox<T>(value: T) {
|
||||
return { value };
|
||||
}
|
||||
const makeHammerBox = makeBox<Hammer>;
|
||||
const makeWrenchBox = makeBox<Wrench>;
|
||||
```
|
||||
|
||||
##### [Optional Variance](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#optional-variance-annotations-for-type-parameters)
|
||||
|
||||
```ts
|
||||
interface Animal {
|
||||
animalStuff: any;
|
||||
}
|
||||
interface Dog extends Animal {
|
||||
dogStuff: any;
|
||||
}
|
||||
type Getter<out T> = () => T;
|
||||
type Setter<in T> = (value: T) => void;
|
||||
```
|
||||
|
||||
##### [`extends` constraints for `infer`](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#extends-constraints-on-infer-type-variables)
|
||||
|
||||
```ts
|
||||
type FirstString<T> = T extends [infer extends string, ...unknown[]]
|
||||
? S
|
||||
: never;
|
||||
```
|
||||
@@ -1,19 +0,0 @@
|
||||
#### fix formatting for typescript Enum with computed members (#12930 by @HosokawaR)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```tsx
|
||||
// Input
|
||||
enum A {
|
||||
[i++],
|
||||
}
|
||||
|
||||
// Prettier stable
|
||||
enum A {
|
||||
i++,
|
||||
}
|
||||
|
||||
// Prettier main
|
||||
enum A {
|
||||
[i++],
|
||||
}
|
||||
```
|
||||
@@ -1,31 +0,0 @@
|
||||
#### Allow formatting for Vue template expression written in TypeScript (#12584 by @sosukesuzuki)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```vue
|
||||
<!-- input -->
|
||||
<script setup lang="ts">
|
||||
let x: string | number = 1
|
||||
</script>
|
||||
|
||||
<template>
|
||||
{{ (x as number).toFixed(2) }}
|
||||
</template>
|
||||
|
||||
<!-- Prettier stable -->
|
||||
<script setup lang="ts">
|
||||
let x: string | number = 1
|
||||
</script>
|
||||
|
||||
<template>
|
||||
{{ (x as number).toFixed(2) }}
|
||||
</template>
|
||||
|
||||
<!-- Prettier main -->
|
||||
<script setup lang="ts">
|
||||
let x: string | number = 1;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
{{ (x as number).toFixed(2) }}
|
||||
</template>
|
||||
```
|
||||
@@ -1,3 +0,0 @@
|
||||
#### Infer Stylus parser for Vue SFC style block (#12707 by @lsdsjy)
|
||||
|
||||
`<style lang="stylus">` blocks in Vue SFCs can be processed by the appropriate plugin if any.
|
||||
@@ -1,19 +0,0 @@
|
||||
#### Avoid printing attribute per line in Vue SFC blocks (#12895 by @sosukesuzuki)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```vue
|
||||
<!-- Input (singleAttributePerLine: true) -->
|
||||
<script lang="ts" setup>
|
||||
</script>
|
||||
|
||||
<!-- Prettier stable -->
|
||||
<script
|
||||
lang="ts"
|
||||
setup
|
||||
>
|
||||
</script>
|
||||
|
||||
<!-- Prettier main -->
|
||||
<script lang="ts" setup>
|
||||
</script>
|
||||
```
|
||||
@@ -292,6 +292,7 @@
|
||||
"sandhose",
|
||||
"Sapegin",
|
||||
"sbdchd",
|
||||
"sdbm",
|
||||
"scandir",
|
||||
"Serializers",
|
||||
"setlocal",
|
||||
|
||||
+14
-14
@@ -109,20 +109,20 @@ The support information looks like this:
|
||||
```typescript
|
||||
{
|
||||
languages: Array<{
|
||||
name: string,
|
||||
since?: string,
|
||||
parsers: string[],
|
||||
group?: string,
|
||||
tmScope?: string,
|
||||
aceMode?: string,
|
||||
codemirrorMode?: string,
|
||||
codemirrorMimeType?: string,
|
||||
aliases?: string[],
|
||||
extensions?: string[],
|
||||
filenames?: string[],
|
||||
linguistLanguageId?: number,
|
||||
vscodeLanguageIds?: string[],
|
||||
}>
|
||||
name: string;
|
||||
since?: string;
|
||||
parsers: string[];
|
||||
group?: string;
|
||||
tmScope?: string;
|
||||
aceMode?: string;
|
||||
codemirrorMode?: string;
|
||||
codemirrorMimeType?: string;
|
||||
aliases?: string[];
|
||||
extensions?: string[];
|
||||
filenames?: string[];
|
||||
linguistLanguageId?: number;
|
||||
vscodeLanguageIds?: string[];
|
||||
}>;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
+13
-13
@@ -32,8 +32,8 @@ See below for examples.
|
||||
### Global
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/prettier@2.6.2/standalone.js"></script>
|
||||
<script src="https://unpkg.com/prettier@2.6.2/parser-graphql.js"></script>
|
||||
<script src="https://unpkg.com/prettier@2.7.1/standalone.js"></script>
|
||||
<script src="https://unpkg.com/prettier@2.7.1/parser-graphql.js"></script>
|
||||
<script>
|
||||
prettier.format("type Query { hello: String }", {
|
||||
parser: "graphql",
|
||||
@@ -48,8 +48,8 @@ Note that the [`unpkg` field](https://unpkg.com/#examples) in Prettier’s `pack
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import * as prettier from "https://unpkg.com/prettier@2.6.2/esm/standalone.mjs";
|
||||
import parserGraphql from "https://unpkg.com/prettier@2.6.2/esm/parser-graphql.mjs";
|
||||
import * as prettier from "https://unpkg.com/prettier@2.7.1/esm/standalone.mjs";
|
||||
import parserGraphql from "https://unpkg.com/prettier@2.7.1/esm/parser-graphql.mjs";
|
||||
|
||||
prettier.format("type Query { hello: String }", {
|
||||
parser: "graphql",
|
||||
@@ -62,8 +62,8 @@ Note that the [`unpkg` field](https://unpkg.com/#examples) in Prettier’s `pack
|
||||
|
||||
```js
|
||||
define([
|
||||
"https://unpkg.com/prettier@2.6.2/standalone.js",
|
||||
"https://unpkg.com/prettier@2.6.2/parser-graphql.js",
|
||||
"https://unpkg.com/prettier@2.7.1/standalone.js",
|
||||
"https://unpkg.com/prettier@2.7.1/parser-graphql.js",
|
||||
], (prettier, ...plugins) => {
|
||||
prettier.format("type Query { hello: String }", {
|
||||
parser: "graphql",
|
||||
@@ -88,8 +88,8 @@ This syntax doesn’t necessarily work in the browser, but it can be used when b
|
||||
### Worker
|
||||
|
||||
```js
|
||||
importScripts("https://unpkg.com/prettier@2.6.2/standalone.js");
|
||||
importScripts("https://unpkg.com/prettier@2.6.2/parser-graphql.js");
|
||||
importScripts("https://unpkg.com/prettier@2.7.1/standalone.js");
|
||||
importScripts("https://unpkg.com/prettier@2.7.1/parser-graphql.js");
|
||||
prettier.format("type Query { hello: String }", {
|
||||
parser: "graphql",
|
||||
plugins: prettierPlugins,
|
||||
@@ -102,8 +102,8 @@ If you want to format [embedded code](options.md#embedded-language-formatting),
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import * as prettier from "https://unpkg.com/prettier@2.6.2/esm/standalone.mjs";
|
||||
import parserBabel from "https://unpkg.com/prettier@2.6.2/esm/parser-babel.mjs";
|
||||
import * as prettier from "https://unpkg.com/prettier@2.7.1/esm/standalone.mjs";
|
||||
import parserBabel from "https://unpkg.com/prettier@2.7.1/esm/parser-babel.mjs";
|
||||
|
||||
console.log(
|
||||
prettier.format("const html=/* HTML */ `<DIV> </DIV>`", {
|
||||
@@ -119,9 +119,9 @@ The HTML code embedded in JavaScript stays unformatted because the `html` parser
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import * as prettier from "https://unpkg.com/prettier@2.6.2/esm/standalone.mjs";
|
||||
import parserBabel from "https://unpkg.com/prettier@2.6.2/esm/parser-babel.mjs";
|
||||
import parserHtml from "https://unpkg.com/prettier@2.6.2/esm/parser-html.mjs";
|
||||
import * as prettier from "https://unpkg.com/prettier@2.7.1/esm/standalone.mjs";
|
||||
import parserBabel from "https://unpkg.com/prettier@2.7.1/esm/parser-babel.mjs";
|
||||
import parserHtml from "https://unpkg.com/prettier@2.7.1/esm/parser-html.mjs";
|
||||
|
||||
console.log(
|
||||
prettier.format("const html=/* HTML */ `<DIV> </DIV>`", {
|
||||
|
||||
+32
@@ -204,3 +204,35 @@ Prevent errors when pattern is unmatched.
|
||||
## `--no-plugin-search`
|
||||
|
||||
Disable plugin autoloading.
|
||||
|
||||
## `--cache`
|
||||
|
||||
If this option is enabled, the following values are used as cache keys and the file is formatted only if one of them is changed.
|
||||
|
||||
- Prettier version
|
||||
- Options
|
||||
- Node.js version
|
||||
- (if `--cache-strategy` is `metadata`) file metadata, such as timestamps
|
||||
- (if `--cache-strategy` is `content`) content of the file
|
||||
|
||||
```bash
|
||||
prettier --write --cache src
|
||||
```
|
||||
|
||||
Running Prettier without `--cache` will delete the cache.
|
||||
|
||||
Also, since the cache file is stored in `./node_modules/.cache/prettier/.prettier-cache`, so you can use `rm ./node_modules/.cache/prettier/.prettier-cache` to remove it manually.
|
||||
|
||||
> Plugins version and implementation are not used as cache keys. We recommend that you delete the cache when updating plugins.
|
||||
|
||||
## `--cache-strategy`
|
||||
|
||||
Strategy for the cache to use for detecting changed files. Can be either `metadata` or `content`.
|
||||
|
||||
In general, `metadata` is faster. However, `content` is useful for updating the timestamp without changing the file content. This can happen, for example, during git operations such as `git clone`, because it does not track file modification times.
|
||||
|
||||
If no strategy is specified, `content` will be used.
|
||||
|
||||
```bash
|
||||
prettier --write --cache --cache-strategy metadata src
|
||||
```
|
||||
+11
-5
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "prettier",
|
||||
"version": "2.7.0-dev",
|
||||
"version": "2.8.0-dev",
|
||||
"description": "Prettier is an opinionated code formatter",
|
||||
"bin": "./bin/prettier.cjs",
|
||||
"repository": "prettier/prettier",
|
||||
@@ -30,7 +30,7 @@
|
||||
"@typescript-eslint/typescript-estree": "5.27.0",
|
||||
"acorn": "8.7.1",
|
||||
"acorn-jsx": "5.3.2",
|
||||
"angular-estree-parser": "2.5.0",
|
||||
"angular-estree-parser": "2.5.1",
|
||||
"angular-html-parser": "1.8.0",
|
||||
"camelcase": "6.3.0",
|
||||
"chalk": "5.0.1",
|
||||
@@ -47,8 +47,10 @@
|
||||
"esutils": "2.0.3",
|
||||
"fast-glob": "3.2.11",
|
||||
"fast-json-stable-stringify": "2.1.0",
|
||||
"file-entry-cache": "6.0.1",
|
||||
"find-cache-dir": "3.3.2",
|
||||
"find-parent-dir": "0.3.1",
|
||||
"flow-parser": "0.178.1",
|
||||
"flow-parser": "0.180.0",
|
||||
"get-stdin": "8.0.0",
|
||||
"graphql": "16.5.0",
|
||||
"html-element-attributes": "3.1.0",
|
||||
@@ -60,7 +62,7 @@
|
||||
"json5": "2.2.1",
|
||||
"leven": "4.0.0",
|
||||
"lines-and-columns": "2.0.3",
|
||||
"linguist-languages": "7.15.0",
|
||||
"linguist-languages": "7.21.0",
|
||||
"mem": "9.0.2",
|
||||
"meriyah": "4.2.1",
|
||||
"micromatch": "4.0.5",
|
||||
@@ -80,6 +82,7 @@
|
||||
"remark-math": "3.0.1",
|
||||
"remark-parse": "8.0.3",
|
||||
"resolve": "1.22.0",
|
||||
"sdbm": "2.0.0",
|
||||
"semver": "7.3.7",
|
||||
"string-width": "5.0.1",
|
||||
"strip-ansi": "7.0.1",
|
||||
@@ -95,8 +98,11 @@
|
||||
"@esbuild-plugins/node-modules-polyfill": "0.1.4",
|
||||
"@glimmer/reference": "0.84.2",
|
||||
"@types/estree": "0.0.51",
|
||||
"@types/file-entry-cache": "5.0.2",
|
||||
"@types/find-cache-dir": "3.2.1",
|
||||
"@types/jest": "28.1.1",
|
||||
"@typescript-eslint/eslint-plugin": "5.26.0",
|
||||
"babel-jest": "27.5.1",
|
||||
"benchmark": "2.1.4",
|
||||
"browserslist-to-esbuild": "1.1.1",
|
||||
"c8": "7.11.3",
|
||||
@@ -126,7 +132,7 @@
|
||||
"node-fetch": "3.2.4",
|
||||
"npm-run-all": "4.1.5",
|
||||
"path-browserify": "1.0.1",
|
||||
"prettier": "2.6.2",
|
||||
"prettier": "2.7.1",
|
||||
"pretty-bytes": "6.0.0",
|
||||
"rimraf": "3.0.2",
|
||||
"rollup-plugin-license": "2.8.1",
|
||||
|
||||
@@ -14,10 +14,15 @@ async function run() {
|
||||
const { runGit, readJson } = await import("./utils.js");
|
||||
|
||||
const params = minimist(process.argv.slice(2), {
|
||||
string: ["version"],
|
||||
boolean: ["dry", "manual"],
|
||||
string: ["version", "repo"],
|
||||
boolean: ["dry", "manual", "skip-dependencies-install"],
|
||||
alias: { v: "version" },
|
||||
default: { manual: false },
|
||||
default: {
|
||||
manual: false,
|
||||
dry: false,
|
||||
"skip-dependencies-install": false,
|
||||
repo: "git@github.com:prettier/prettier.git",
|
||||
},
|
||||
});
|
||||
|
||||
const { stdout: previousVersion } = await runGit([
|
||||
@@ -39,7 +44,7 @@ async function run() {
|
||||
[
|
||||
"./steps/validate-new-version.js",
|
||||
"./steps/check-git-status.js",
|
||||
"./steps/install-dependencies.js",
|
||||
!params["skip-dependencies-install"] && "./steps/install-dependencies.js",
|
||||
params.manual && "./steps/run-tests.js",
|
||||
"./steps/update-version.js",
|
||||
params.manual && "./steps/generate-bundles.js",
|
||||
|
||||
@@ -7,7 +7,7 @@ async function format() {
|
||||
await runYarn(["lint:prettier", "--write"]);
|
||||
}
|
||||
|
||||
async function commit(version) {
|
||||
async function commit({ version, repo }) {
|
||||
await runGit(["commit", "-am", `Bump Prettier dependency to ${version}`]);
|
||||
|
||||
// Add rev to `.git-blame-ignore-revs` file
|
||||
@@ -19,7 +19,7 @@ async function commit(version) {
|
||||
fs.writeFileSync(file, text);
|
||||
await runGit(["commit", "-am", `Git blame ignore ${version}`]);
|
||||
|
||||
await runGit(["push"]);
|
||||
await runGit(["push", "--repo", repo]);
|
||||
}
|
||||
|
||||
async function bump({
|
||||
@@ -50,5 +50,5 @@ export default async function bumpPrettier(params) {
|
||||
|
||||
await logPromise("Updating files", format());
|
||||
await logPromise("Bump default branch version", bump(params));
|
||||
await logPromise("Committing changed files", commit(version));
|
||||
await logPromise("Committing changed files", commit(params));
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import { runGit, logPromise } from "../utils.js";
|
||||
|
||||
async function pushGit({ version }) {
|
||||
async function pushGit({ version, repo }) {
|
||||
await runGit(["commit", "-am", `Release ${version}`]);
|
||||
await runGit(["tag", "-a", version, "-m", `Release ${version}`]);
|
||||
await runGit(["push"]);
|
||||
await runGit(["push", "--tags"]);
|
||||
await runGit(["push", "--repo", repo]);
|
||||
await runGit(["push", "--tags", "--repo", repo]);
|
||||
}
|
||||
|
||||
export default function pushToGit(params) {
|
||||
|
||||
@@ -49,6 +49,17 @@ export default async function waitForBotRelease({ dry, version }) {
|
||||
await waitForEnter();
|
||||
}
|
||||
|
||||
console.log(
|
||||
outdentString(chalk/* indent */ `
|
||||
1. Go to {green.underline https://www.npmjs.com/package/prettier/access}
|
||||
2. Make sure "{yellow Publishing access}" section is set to "{yellow Require two-factor authentication or automation tokens}".
|
||||
|
||||
Press ENTER to continue.
|
||||
`)
|
||||
);
|
||||
|
||||
await waitForEnter();
|
||||
|
||||
console.log(
|
||||
outdentString(chalk/* indent */ `
|
||||
1. Go to {green.underline https://github.com/prettier/release-workflow/actions/workflows/release.yml}
|
||||
|
||||
@@ -69,6 +69,25 @@ const categoryOrder = [
|
||||
*/
|
||||
/* eslint sort-keys: "error" */
|
||||
const options = {
|
||||
cache: {
|
||||
default: false,
|
||||
description: "Only format changed files. Cannot use with --stdin-filepath.",
|
||||
type: "boolean",
|
||||
},
|
||||
"cache-strategy": {
|
||||
choices: [
|
||||
{
|
||||
description: "Use the file metadata such as timestamps as cache keys",
|
||||
value: "metadata",
|
||||
},
|
||||
{
|
||||
description: "Use the file content as cache keys",
|
||||
value: "content",
|
||||
},
|
||||
],
|
||||
description: "Strategy for the cache to use for detecting changed files.",
|
||||
type: "choice",
|
||||
},
|
||||
check: {
|
||||
alias: "c",
|
||||
category: coreOptions.CATEGORY_OUTPUT,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import path from "node:path";
|
||||
import { promises as fs } from "node:fs";
|
||||
import fastGlob from "fast-glob";
|
||||
import {statSafe} from "./utils.js"
|
||||
|
||||
/** @typedef {import('./context').Context} Context */
|
||||
|
||||
@@ -171,22 +171,6 @@ function sortPaths(paths) {
|
||||
return paths.sort((a, b) => a.localeCompare(b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stats of a given path.
|
||||
* @param {string} filePath The path to target file.
|
||||
* @returns {Promise<import('fs').Stats | undefined>} The stats.
|
||||
*/
|
||||
async function statSafe(filePath) {
|
||||
try {
|
||||
return await fs.stat(filePath);
|
||||
} catch (error) {
|
||||
/* istanbul ignore next */
|
||||
if (error.code !== "ENOENT") {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function should be replaced with `fastGlob.escapePath` when these issues are fixed:
|
||||
* - https://github.com/mrmlnc/fast-glob/issues/261
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
"use strict";
|
||||
|
||||
const os = require("os");
|
||||
const path = require("path");
|
||||
const findCacheDir = require("find-cache-dir");
|
||||
|
||||
/**
|
||||
* Find default cache file (`./node_modules/.cache/prettier/.prettier-cache`) using https://github.com/avajs/find-cache-dir
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
function findCacheFile() {
|
||||
const cacheDir =
|
||||
findCacheDir({ name: "prettier", create: true }) || os.tmpdir();
|
||||
const cacheFilePath = path.join(cacheDir, ".prettier-cache");
|
||||
return cacheFilePath;
|
||||
}
|
||||
|
||||
module.exports = findCacheFile;
|
||||
@@ -0,0 +1,96 @@
|
||||
"use strict";
|
||||
|
||||
// Inspired by LintResultsCache from ESLint
|
||||
// https://github.com/eslint/eslint/blob/c2d0a830754b6099a3325e6d3348c3ba983a677a/lib/cli-engine/lint-result-cache.js
|
||||
|
||||
const fileEntryCache = require("file-entry-cache");
|
||||
const stringify = require("fast-json-stable-stringify");
|
||||
// eslint-disable-next-line no-restricted-modules
|
||||
const { version: prettierVersion } = require("../index.js");
|
||||
const { createHash } = require("./utils.js");
|
||||
|
||||
const optionsHashCache = new WeakMap();
|
||||
const nodeVersion = process && process.version;
|
||||
|
||||
/**
|
||||
* @param {*} options
|
||||
* @returns {string}
|
||||
*/
|
||||
function getHashOfOptions(options) {
|
||||
if (optionsHashCache.has(options)) {
|
||||
return optionsHashCache.get(options);
|
||||
}
|
||||
const hash = createHash(
|
||||
`${prettierVersion}_${nodeVersion}_${stringify(options)}`
|
||||
);
|
||||
optionsHashCache.set(options, hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {{ hashOfOptions?: string }} OurMeta
|
||||
* @typedef {import("file-entry-cache").FileDescriptor} FileDescriptor
|
||||
*
|
||||
* @param {import("file-entry-cache").FileDescriptor} fileDescriptor
|
||||
* @returns {FileDescriptor["meta"] & OurMeta}
|
||||
*/
|
||||
function getMetadataFromFileDescriptor(fileDescriptor) {
|
||||
return fileDescriptor.meta;
|
||||
}
|
||||
|
||||
class FormatResultsCache {
|
||||
/**
|
||||
* @param {string} cacheFileLocation The path of cache file location. (default: `node_modules/.cache/prettier/prettier-cache`)
|
||||
* @param {string} cacheStrategy
|
||||
*/
|
||||
constructor(cacheFileLocation, cacheStrategy) {
|
||||
const useChecksum = cacheStrategy === "content";
|
||||
|
||||
this.cacheFileLocation = cacheFileLocation;
|
||||
this.fileEntryCache = fileEntryCache.create(
|
||||
/* cacheId */ cacheFileLocation,
|
||||
/* directory */ undefined,
|
||||
useChecksum
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} filePath
|
||||
* @param {any} options
|
||||
*/
|
||||
existsAvailableFormatResultsCache(filePath, options) {
|
||||
const fileDescriptor = this.fileEntryCache.getFileDescriptor(filePath);
|
||||
const hashOfOptions = getHashOfOptions(options);
|
||||
const meta = getMetadataFromFileDescriptor(fileDescriptor);
|
||||
const changed =
|
||||
fileDescriptor.changed || meta.hashOfOptions !== hashOfOptions;
|
||||
|
||||
if (fileDescriptor.notFound) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} filePath
|
||||
* @param {any} options
|
||||
*/
|
||||
setFormatResultsCache(filePath, options) {
|
||||
const fileDescriptor = this.fileEntryCache.getFileDescriptor(filePath);
|
||||
const meta = getMetadataFromFileDescriptor(fileDescriptor);
|
||||
if (fileDescriptor && !fileDescriptor.notFound) {
|
||||
meta.hashOfOptions = getHashOfOptions(options);
|
||||
}
|
||||
}
|
||||
|
||||
reconcile() {
|
||||
this.fileEntryCache.reconcile();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FormatResultsCache;
|
||||
+46
-1
@@ -7,6 +7,9 @@ import { createIgnorer, errors } from "./prettier-internal.js";
|
||||
import { expandPatterns, fixWindowsSlashes } from "./expand-patterns.js";
|
||||
import getOptionsForFile from "./options/get-options-for-file.js";
|
||||
import isTTY from "./is-tty.js";
|
||||
import findCacheFile from "./find-cache-file.js";
|
||||
import FormatResultsCache from "./format-results-cache.js";
|
||||
import { statSafe } from "./utils.js";
|
||||
|
||||
const { getStdin } = thirdParty;
|
||||
|
||||
@@ -301,6 +304,26 @@ async function formatFiles(context) {
|
||||
context.logger.log("Checking formatting...");
|
||||
}
|
||||
|
||||
let formatResultsCache;
|
||||
const cacheFilePath = findCacheFile();
|
||||
if (context.argv.cache) {
|
||||
formatResultsCache = new FormatResultsCache(
|
||||
cacheFilePath,
|
||||
context.argv.cacheStrategy || "content"
|
||||
);
|
||||
} else {
|
||||
if (context.argv.cacheStrategy) {
|
||||
context.logger.error(
|
||||
"`--cache-strategy` cannot be used without `--cache`."
|
||||
);
|
||||
process.exit(2);
|
||||
}
|
||||
const stat = await statSafe(cacheFilePath);
|
||||
if (stat) {
|
||||
await fs.unlink(cacheFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
for await (const pathOrError of expandPatterns(context)) {
|
||||
if (typeof pathOrError === "object") {
|
||||
context.logger.error(pathOrError.error);
|
||||
@@ -368,17 +391,32 @@ async function formatFiles(context) {
|
||||
|
||||
const start = Date.now();
|
||||
|
||||
const isCacheExists = formatResultsCache?.existsAvailableFormatResultsCache(
|
||||
filename,
|
||||
options
|
||||
);
|
||||
|
||||
let result;
|
||||
let output;
|
||||
|
||||
try {
|
||||
<<<<<<< HEAD
|
||||
result = await format(context, input, options);
|
||||
=======
|
||||
if (isCacheExists) {
|
||||
result = { formatted: input };
|
||||
} else {
|
||||
result = format(context, input, options);
|
||||
}
|
||||
>>>>>>> main
|
||||
output = result.formatted;
|
||||
} catch (error) {
|
||||
handleError(context, filename, error, printedFilename);
|
||||
continue;
|
||||
}
|
||||
|
||||
formatResultsCache?.setFormatResultsCache(filename, options);
|
||||
|
||||
const isDifferent = output !== input;
|
||||
|
||||
if (printedFilename) {
|
||||
@@ -414,7 +452,12 @@ async function formatFiles(context) {
|
||||
process.exitCode = 2;
|
||||
}
|
||||
} else if (!context.argv.check && !context.argv.listDifferent) {
|
||||
context.logger.log(`${chalk.grey(filename)} ${Date.now() - start}ms`);
|
||||
const message = `${chalk.grey(filename)} ${Date.now() - start}ms`;
|
||||
if (isCacheExists) {
|
||||
context.logger.log(`${message} (cached)`);
|
||||
} else {
|
||||
context.logger.log(message);
|
||||
}
|
||||
}
|
||||
} else if (context.argv.debugCheck) {
|
||||
/* istanbul ignore else */
|
||||
@@ -437,6 +480,8 @@ async function formatFiles(context) {
|
||||
}
|
||||
}
|
||||
|
||||
formatResultsCache?.reconcile();
|
||||
|
||||
// Print check summary based on expected exit code
|
||||
if (context.argv.check) {
|
||||
if (numberOfUnformattedFilesFound === 0) {
|
||||
|
||||
@@ -93,6 +93,10 @@ async function main(context) {
|
||||
} else if (context.argv.fileInfo) {
|
||||
await logFileInfoOrDie(context);
|
||||
} else if (useStdin) {
|
||||
if (context.argv.cache) {
|
||||
context.logger.error("`--cache` cannot be used with stdin.");
|
||||
process.exit(2);
|
||||
}
|
||||
await formatStdin(context);
|
||||
} else if (hasFilePatterns) {
|
||||
await formatFiles(context);
|
||||
|
||||
@@ -2,6 +2,11 @@ import { __internal as sharedWithCli } from "../index.js";
|
||||
|
||||
const { arrayify, getLast, isNonEmptyArray, partition } = sharedWithCli.utils;
|
||||
|
||||
const { promises: fs } = require("fs");
|
||||
|
||||
// eslint-disable-next-line no-restricted-modules
|
||||
const { default: sdbm } = require("../../vendors/sdbm.js");
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
const printToScreen = console.log.bind(console);
|
||||
|
||||
@@ -40,6 +45,30 @@ function pick(object, keys) {
|
||||
return Object.fromEntries(entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} source
|
||||
* @returns {string}
|
||||
*/
|
||||
function createHash(source) {
|
||||
return String(sdbm(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stats of a given path.
|
||||
* @param {string} filePath The path to target file.
|
||||
* @returns {Promise<import('fs').Stats | undefined>} The stats.
|
||||
*/
|
||||
async function statSafe(filePath) {
|
||||
try {
|
||||
return await fs.stat(filePath);
|
||||
} catch (error) {
|
||||
/* istanbul ignore next */
|
||||
if (error.code !== "ENOENT") {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
arrayify,
|
||||
getLast,
|
||||
@@ -48,4 +77,5 @@ export {
|
||||
printToScreen,
|
||||
groupBy,
|
||||
pick,
|
||||
createHash, statSafe
|
||||
};
|
||||
@@ -134,10 +134,11 @@ function genericPrint(path, options, print) {
|
||||
lines[0] = lines[0].trim();
|
||||
}
|
||||
|
||||
return join(
|
||||
hardline,
|
||||
['"""', ...(lines.length > 0 ? lines : []), '"""'].filter(Boolean)
|
||||
);
|
||||
if (lines.every((line) => line === "")) {
|
||||
lines.length = 0;
|
||||
}
|
||||
|
||||
return join(hardline, ['"""', ...lines, '"""']);
|
||||
}
|
||||
return [
|
||||
'"',
|
||||
|
||||
@@ -64,7 +64,6 @@ const languages = [
|
||||
since: "1.4.0",
|
||||
parsers: ["typescript", "babel-ts"],
|
||||
vscodeLanguageIds: ["typescript"],
|
||||
extensions: [...data.extensions, ".mts", ".cts"],
|
||||
})),
|
||||
createLanguage(linguistLanguages.TSX, () => ({
|
||||
since: "1.4.0",
|
||||
|
||||
@@ -4,6 +4,7 @@ import isTypeCastComment from "../../utils/is-type-cast-comment.js";
|
||||
import getLast from "../../../utils/get-last.js";
|
||||
import visitNode from "./visit-node.js";
|
||||
import { throwErrorForInvalidNodes } from "./typescript.js";
|
||||
import throwSyntaxError from "./throw-syntax-error.js";
|
||||
|
||||
function postprocess(ast, options) {
|
||||
if (
|
||||
@@ -100,6 +101,20 @@ function postprocess(ast, options) {
|
||||
};
|
||||
}
|
||||
break;
|
||||
case "ObjectExpression":
|
||||
// #12963
|
||||
if (options.parser === "typescript") {
|
||||
const invalidProperty = node.properties.find(
|
||||
(property) =>
|
||||
property.type === "Property" &&
|
||||
property.value.type === "TSEmptyBodyFunctionExpression"
|
||||
);
|
||||
if (invalidProperty) {
|
||||
throwSyntaxError(invalidProperty.value, "Unexpected token.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "SequenceExpression": {
|
||||
// Babel (unlike other parsers) includes spaces and comments in the range. Let's unify this.
|
||||
const lastExpression = getLast(node.expressions);
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
const createError = require("../../../common/parser-create-error.js");
|
||||
|
||||
function throwSyntaxError(node, message) {
|
||||
const { start, end } = node.loc;
|
||||
throw createError(message, {
|
||||
start: { line: start.line, column: start.column + 1 },
|
||||
end: { line: end.line, column: end.column + 1 },
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = throwSyntaxError;
|
||||
@@ -1,13 +1,5 @@
|
||||
import createError from "../../../common/parser-create-error.js";
|
||||
import visitNode from "./visit-node.js";
|
||||
|
||||
function throwSyntaxError(node, message) {
|
||||
const { start, end } = node.loc;
|
||||
throw createError(message, {
|
||||
start: { line: start.line, column: start.column + 1 },
|
||||
end: { line: end.line, column: end.column + 1 },
|
||||
});
|
||||
}
|
||||
import throwSyntaxError from "./throw-syntax-error.js";
|
||||
|
||||
// Invalid decorators are removed since `@typescript-eslint/typescript-estree` v4
|
||||
// https://github.com/typescript-eslint/typescript-eslint/pull/2375
|
||||
@@ -71,6 +63,7 @@ function throwErrorForInvalidNodes(ast, options) {
|
||||
if (esTreeNode !== node) {
|
||||
return;
|
||||
}
|
||||
|
||||
throwErrorForInvalidDecorator(tsNode, esTreeNode, tsNodeToESTreeNodeMap);
|
||||
throwErrorForInvalidAbstractProperty(tsNode, esTreeNode);
|
||||
});
|
||||
|
||||
@@ -51,11 +51,6 @@ function printTypeAnnotation(path, options, print) {
|
||||
|
||||
const parentNode = path.getParentNode();
|
||||
|
||||
// Workaround for https://github.com/babel/babel/issues/14498
|
||||
if (parentNode.type === "ArrayPattern" && options.parser === "babel-ts") {
|
||||
return [" as ", print("typeAnnotation")];
|
||||
}
|
||||
|
||||
const isFunctionDeclarationIdentifier =
|
||||
parentNode.type === "DeclareFunction" && parentNode.id === node;
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`basic.html format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["angular"]
|
||||
printWidth: 80
|
||||
| printWidth
|
||||
=====================================input======================================
|
||||
<ng-container *ngTemplateOutlet="someTmpl; context: {app}"></ng-container>
|
||||
|
||||
=====================================output=====================================
|
||||
<ng-container *ngTemplateOutlet="someTmpl; context: { app }"></ng-container>
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
@@ -0,0 +1 @@
|
||||
<ng-container *ngTemplateOutlet="someTmpl; context: {app}"></ng-container>
|
||||
@@ -0,0 +1 @@
|
||||
run_spec(__dirname, ["angular"]);
|
||||
@@ -32,6 +32,55 @@ type Person {name: String}
|
||||
"""
|
||||
type Person {name: String}
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
Empty lines before
|
||||
"""
|
||||
type Person {name: String}
|
||||
|
||||
"""
|
||||
Empty lines after
|
||||
|
||||
|
||||
"""
|
||||
type Person {name: String}
|
||||
|
||||
"""
|
||||
|
||||
|
||||
Empty lines around
|
||||
|
||||
|
||||
"""
|
||||
type Person {name: String}
|
||||
|
||||
"""
|
||||
First line
|
||||
|
||||
Second Line
|
||||
"""
|
||||
type Person {name: String}
|
||||
|
||||
"""
|
||||
|
||||
|
||||
First line
|
||||
|
||||
Second Line
|
||||
"""
|
||||
type Person {name: String}
|
||||
|
||||
"""
|
||||
First line
|
||||
|
||||
Second Line
|
||||
|
||||
|
||||
"""
|
||||
type Person {name: String}
|
||||
|
||||
=====================================output=====================================
|
||||
"""
|
||||
Customer
|
||||
@@ -74,6 +123,54 @@ type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
"""
|
||||
Empty lines before
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
"""
|
||||
Empty lines after
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
"""
|
||||
Empty lines around
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
"""
|
||||
First line
|
||||
|
||||
Second Line
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
"""
|
||||
First line
|
||||
|
||||
Second Line
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
"""
|
||||
First line
|
||||
|
||||
Second Line
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
|
||||
@@ -23,3 +23,52 @@ type Person {name: String}
|
||||
2
|
||||
"""
|
||||
type Person {name: String}
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
Empty lines before
|
||||
"""
|
||||
type Person {name: String}
|
||||
|
||||
"""
|
||||
Empty lines after
|
||||
|
||||
|
||||
"""
|
||||
type Person {name: String}
|
||||
|
||||
"""
|
||||
|
||||
|
||||
Empty lines around
|
||||
|
||||
|
||||
"""
|
||||
type Person {name: String}
|
||||
|
||||
"""
|
||||
First line
|
||||
|
||||
Second Line
|
||||
"""
|
||||
type Person {name: String}
|
||||
|
||||
"""
|
||||
|
||||
|
||||
First line
|
||||
|
||||
Second Line
|
||||
"""
|
||||
type Person {name: String}
|
||||
|
||||
"""
|
||||
First line
|
||||
|
||||
Second Line
|
||||
|
||||
|
||||
"""
|
||||
type Person {name: String}
|
||||
@@ -1,12 +1,5 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`d-flag.js [flow] format 1`] = `
|
||||
"Invalid flags supplied to RegExp constructor 'd' (1:5)
|
||||
> 1 | /./d;
|
||||
| ^
|
||||
2 |"
|
||||
`;
|
||||
|
||||
exports[`d-flag.js [meriyah] format 1`] = `
|
||||
"Unexpected regular expression flag (1:3)
|
||||
> 1 | /./d;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
run_spec(import.meta, ["babel", "flow", "typescript"], {
|
||||
errors: {
|
||||
flow: ["d-flag.js", "v-flag.js"],
|
||||
flow: ["v-flag.js"],
|
||||
acorn: ["v-flag.js"],
|
||||
espree: ["v-flag.js"],
|
||||
meriyah: ["d-flag.js", "v-flag.js"],
|
||||
|
||||
@@ -9,7 +9,7 @@ exports[`async-arrow-invalid.js [flow] format 1`] = `
|
||||
`;
|
||||
|
||||
exports[`default-escaped.js [flow] format 1`] = `
|
||||
"Unexpected identifier, expected the token \`{\` (1:8)
|
||||
"Unexpected token \`async\`, expected a declaration, statement or export specifiers (1:8)
|
||||
> 1 | export asyn\\u{63} from "async";
|
||||
| ^^^^^^^^^^
|
||||
2 |"
|
||||
|
||||
@@ -127,7 +127,7 @@ exports[`snippet: #1 [espree] format 1`] = `
|
||||
`;
|
||||
|
||||
exports[`snippet: #1 [flow] format 1`] = `
|
||||
"Unexpected token \`switch\` (1:7)
|
||||
"Unexpected token \`switch\`, expected an identifier (1:7)
|
||||
> 1 | class switch() {}
|
||||
| ^^^^^^"
|
||||
`;
|
||||
@@ -156,92 +156,236 @@ exports[`snippet: #1 [typescript] format 1`] = `
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #2 [acorn] format 1`] = `
|
||||
"Unexpected token (1:13)
|
||||
> 1 | ({ method() })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #2 [babel] format 1`] = `
|
||||
"Unexpected token, expected "{" (1:13)
|
||||
> 1 | ({ method() })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #2 [babel] format 2`] = `
|
||||
"Invalid parenthesized assignment pattern. (1:1)
|
||||
> 1 | (a = 1) = 2
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #2 [babel-flow] format 1`] = `
|
||||
"Unexpected token, expected "{" (1:13)
|
||||
> 1 | ({ method() })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #2 [babel-flow] format 2`] = `
|
||||
"Invalid parenthesized assignment pattern. (1:1)
|
||||
> 1 | (a = 1) = 2
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #2 [babel-ts] format 1`] = `
|
||||
"Unexpected token, expected "{" (1:13)
|
||||
> 1 | ({ method() })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #2 [babel-ts] format 2`] = `
|
||||
"Invalid parenthesized assignment pattern. (1:1)
|
||||
> 1 | (a = 1) = 2
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #2 [espree] format 1`] = `
|
||||
"Unexpected token } (1:13)
|
||||
> 1 | ({ method() })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #2 [flow] format 1`] = `
|
||||
"Unexpected token \`}\`, expected the token \`{\` (1:13)
|
||||
> 1 | ({ method() })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #2 [flow] format 2`] = `
|
||||
"Invalid left-hand side in assignment (1:2)
|
||||
> 1 | (a = 1) = 2
|
||||
| ^^^^^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #2 [meriyah] format 1`] = `
|
||||
"Expected '{' (1:13)
|
||||
> 1 | ({ method() })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #2 [meriyah] format 2`] = `
|
||||
"Invalid left-hand side in assignment (1:9)
|
||||
> 1 | (a = 1) = 2
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #2 [typescript] format 1`] = `
|
||||
"Unexpected token. (1:10)
|
||||
> 1 | ({ method() })
|
||||
| ^^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #3 [acorn] format 1`] = `
|
||||
"Unexpected token (1:15)
|
||||
> 1 | ({ method({}) })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #3 [babel] format 1`] = `
|
||||
"Unexpected token, expected "{" (1:15)
|
||||
> 1 | ({ method({}) })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #3 [babel] format 2`] = `
|
||||
"Invalid parenthesized assignment pattern. (1:1)
|
||||
> 1 | (a += b) = 1
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #3 [babel-flow] format 1`] = `
|
||||
"Unexpected token, expected "{" (1:15)
|
||||
> 1 | ({ method({}) })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #3 [babel-flow] format 2`] = `
|
||||
"Invalid parenthesized assignment pattern. (1:1)
|
||||
> 1 | (a += b) = 1
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #3 [babel-ts] format 1`] = `
|
||||
"Unexpected token, expected "{" (1:15)
|
||||
> 1 | ({ method({}) })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #3 [babel-ts] format 2`] = `
|
||||
"Invalid parenthesized assignment pattern. (1:1)
|
||||
> 1 | (a += b) = 1
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #3 [espree] format 1`] = `
|
||||
"Unexpected token } (1:15)
|
||||
> 1 | ({ method({}) })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #3 [flow] format 1`] = `
|
||||
"Unexpected token \`}\`, expected the token \`{\` (1:15)
|
||||
> 1 | ({ method({}) })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #3 [flow] format 2`] = `
|
||||
"Invalid left-hand side in assignment (1:2)
|
||||
> 1 | (a += b) = 1
|
||||
| ^^^^^^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #3 [meriyah] format 1`] = `
|
||||
"Expected '{' (1:15)
|
||||
> 1 | ({ method({}) })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #3 [meriyah] format 2`] = `
|
||||
"Invalid left-hand side in assignment (1:10)
|
||||
> 1 | (a += b) = 1
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #3 [typescript] format 1`] = `
|
||||
"Unexpected token. (1:10)
|
||||
> 1 | ({ method({}) })
|
||||
| ^^^^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #4 [acorn] format 1`] = `
|
||||
"Unexpected token (1:23)
|
||||
> 1 | ({ method(parameter,) })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #4 [babel] format 1`] = `
|
||||
"Unexpected token, expected "{" (1:23)
|
||||
> 1 | ({ method(parameter,) })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #4 [babel] format 2`] = `
|
||||
"Invalid left-hand side in parenthesized expression. (1:2)
|
||||
> 1 | (a = b) += 1
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #4 [babel-flow] format 1`] = `
|
||||
"Unexpected token, expected "{" (1:23)
|
||||
> 1 | ({ method(parameter,) })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #4 [babel-flow] format 2`] = `
|
||||
"Invalid left-hand side in parenthesized expression. (1:2)
|
||||
> 1 | (a = b) += 1
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #4 [babel-ts] format 1`] = `
|
||||
"Unexpected token, expected "{" (1:23)
|
||||
> 1 | ({ method(parameter,) })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #4 [babel-ts] format 2`] = `
|
||||
"Invalid left-hand side in parenthesized expression. (1:2)
|
||||
> 1 | (a = b) += 1
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #4 [espree] format 1`] = `
|
||||
"Unexpected token } (1:23)
|
||||
> 1 | ({ method(parameter,) })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #4 [flow] format 1`] = `
|
||||
"Unexpected token \`}\`, expected the token \`{\` (1:23)
|
||||
> 1 | ({ method(parameter,) })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #4 [flow] format 2`] = `
|
||||
"Invalid left-hand side in assignment (1:2)
|
||||
> 1 | (a = b) += 1
|
||||
| ^^^^^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #4 [meriyah] format 1`] = `
|
||||
"Expected '{' (1:23)
|
||||
> 1 | ({ method(parameter,) })
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #4 [meriyah] format 2`] = `
|
||||
"Invalid left-hand side in assignment (1:10)
|
||||
> 1 | (a = b) += 1
|
||||
| ^"
|
||||
`;
|
||||
|
||||
exports[`snippet: #4 [typescript] format 1`] = `
|
||||
"Unexpected token. (1:10)
|
||||
> 1 | ({ method(parameter,) })
|
||||
| ^^^^^^^^^^^^"
|
||||
`;
|
||||
@@ -1,7 +1,13 @@
|
||||
run_spec(
|
||||
{
|
||||
importMeta: import.meta,
|
||||
snippets: ["for each (a in b) {}", "class switch() {}"],
|
||||
snippets: [
|
||||
"for each (a in b) {}",
|
||||
"class switch() {}",
|
||||
"({ method() })",
|
||||
"({ method({}) })",
|
||||
"({ method(parameter,) })",
|
||||
],
|
||||
},
|
||||
[
|
||||
"babel",
|
||||
|
||||
@@ -139,6 +139,10 @@ Editor options:
|
||||
|
||||
Other options:
|
||||
|
||||
--cache Only format changed files. Cannot use with --stdin-filepath.
|
||||
Defaults to false.
|
||||
--cache-strategy <metadata|content>
|
||||
Strategy for the cache to use for detecting changed files.
|
||||
--no-color Do not colorize error messages.
|
||||
--no-error-on-unmatched-pattern
|
||||
Prevent errors when pattern is unmatched.
|
||||
@@ -309,6 +313,10 @@ Editor options:
|
||||
|
||||
Other options:
|
||||
|
||||
--cache Only format changed files. Cannot use with --stdin-filepath.
|
||||
Defaults to false.
|
||||
--cache-strategy <metadata|content>
|
||||
Strategy for the cache to use for detecting changed files.
|
||||
--no-color Do not colorize error messages.
|
||||
--no-error-on-unmatched-pattern
|
||||
Prevent errors when pattern is unmatched.
|
||||
|
||||
@@ -44,6 +44,35 @@ Default: true
|
||||
|
||||
exports[`show detailed usage with --help bracket-spacing (write) 1`] = `[]`;
|
||||
|
||||
exports[`show detailed usage with --help cache (stderr) 1`] = `""`;
|
||||
|
||||
exports[`show detailed usage with --help cache (stdout) 1`] = `
|
||||
"--cache
|
||||
|
||||
Only format changed files. Cannot use with --stdin-filepath.
|
||||
|
||||
Default: false
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`show detailed usage with --help cache (write) 1`] = `[]`;
|
||||
|
||||
exports[`show detailed usage with --help cache-strategy (stderr) 1`] = `""`;
|
||||
|
||||
exports[`show detailed usage with --help cache-strategy (stdout) 1`] = `
|
||||
"--cache-strategy <metadata|content>
|
||||
|
||||
Strategy for the cache to use for detecting changed files.
|
||||
|
||||
Valid options:
|
||||
|
||||
metadata Use the file metadata such as timestamps as cache keys
|
||||
content Use the file content as cache keys
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`show detailed usage with --help cache-strategy (write) 1`] = `[]`;
|
||||
|
||||
exports[`show detailed usage with --help check (stderr) 1`] = `""`;
|
||||
|
||||
exports[`show detailed usage with --help check (stdout) 1`] = `
|
||||
|
||||
@@ -0,0 +1,373 @@
|
||||
"use strict";
|
||||
|
||||
const path = require("path");
|
||||
const { promises: fs } = require("fs");
|
||||
const rimraf = require("rimraf");
|
||||
const { default: stripAnsi } = require("../../../vendors/strip-ansi.js");
|
||||
|
||||
const runPrettier = require("../run-prettier.js");
|
||||
|
||||
function resolveDir(dir) {
|
||||
return path.join(__dirname, "..", dir);
|
||||
}
|
||||
|
||||
describe("--cache option", () => {
|
||||
const dir = resolveDir("cli/cache");
|
||||
const defaultCacheFile = path.join(
|
||||
dir,
|
||||
"node_modules/.cache/prettier/.prettier-cache"
|
||||
);
|
||||
|
||||
let contentA;
|
||||
let contentB;
|
||||
|
||||
beforeAll(async () => {
|
||||
contentA = await fs.readFile(path.join(dir, "a.js"), "utf8");
|
||||
contentB = await fs.readFile(path.join(dir, "b.js"), "utf8");
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
rimraf.sync(path.join(dir, "node_modules"));
|
||||
await fs.writeFile(path.join(dir, "a.js"), contentA);
|
||||
await fs.writeFile(path.join(dir, "b.js"), contentB);
|
||||
});
|
||||
|
||||
it("throw error when cache-strategy is invalid", async () => {
|
||||
const { stderr } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--cache-strategy",
|
||||
"invalid",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(stderr.trim())).toBe(
|
||||
'[error] Invalid --cache-strategy value. Expected "content" or "metadata", but received "invalid".'
|
||||
);
|
||||
});
|
||||
|
||||
it("throws error when use with --stdin-filepath", async () => {
|
||||
const { stderr } = await runPrettier(
|
||||
dir,
|
||||
["--cache", "--stdin-filepath", "foo.js"],
|
||||
{ input: "const a = a;" }
|
||||
);
|
||||
expect(stripAnsi(stderr.trim())).toBe(
|
||||
"[error] `--cache` cannot be used with stdin."
|
||||
);
|
||||
});
|
||||
|
||||
it("throws error when use `--cache-strategy` without `--cache`.", async () => {
|
||||
const { stderr } = await runPrettier(
|
||||
dir,
|
||||
["foo.js", "--cache-strategy", "content"],
|
||||
{
|
||||
input: "const a = a;",
|
||||
}
|
||||
);
|
||||
expect(stripAnsi(stderr.trim())).toBe(
|
||||
"[error] `--cache-strategy` cannot be used without `--cache`."
|
||||
);
|
||||
});
|
||||
|
||||
describe("--cache-strategy metadata", () => {
|
||||
it("creates default cache file named `node_modules/.cache/prettier/.prettier-cache`", async () => {
|
||||
await expect(fs.stat(defaultCacheFile)).rejects.toHaveProperty(
|
||||
"code",
|
||||
"ENOENT"
|
||||
);
|
||||
await runPrettier(dir, ["--cache", "--cache-strategy", "metadata", "."]);
|
||||
await expect(fs.stat(defaultCacheFile)).resolves.not.toThrowError();
|
||||
});
|
||||
|
||||
it("does'nt format when cache is available", async () => {
|
||||
const { stdout: firstStdout } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--write",
|
||||
"--cache-strategy",
|
||||
"metadata",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(firstStdout).split("\n").filter(Boolean)).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/^a\.js .+ms$/),
|
||||
expect.stringMatching(/^b\.js .+ms$/),
|
||||
])
|
||||
);
|
||||
|
||||
const { stdout: secondStdout } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--write",
|
||||
"--cache-strategy",
|
||||
"metadata",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(secondStdout).split("\n").filter(Boolean)).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/^a\.js .+ms \(cached\)$/),
|
||||
expect.stringMatching(/^b\.js .+ms \(cached\)$/),
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it("re-formats when a file has been updated.", async () => {
|
||||
const { stdout: firstStdout } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--write",
|
||||
"--cache-strategy",
|
||||
"metadata",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(firstStdout).split("\n").filter(Boolean)).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/^a\.js .+ms$/),
|
||||
expect.stringMatching(/^b\.js .+ms$/),
|
||||
])
|
||||
);
|
||||
|
||||
// Update `a.js`
|
||||
await fs.writeFile(path.join(dir, "a.js"), "const a = `a`;");
|
||||
|
||||
const { stdout: secondStdout } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--write",
|
||||
"--cache-strategy",
|
||||
"metadata",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(secondStdout).split("\n").filter(Boolean)).toEqual(
|
||||
// the cache of `b.js` is only available.
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/^a\.js .+ms$/),
|
||||
expect.stringMatching(/^b\.js .+ms \(cached\)$/),
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it("re-formats when timestamp has been updated", async () => {
|
||||
const { stdout: firstStdout } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--write",
|
||||
"--cache-strategy",
|
||||
"metadata",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(firstStdout).split("\n").filter(Boolean)).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/^a\.js .+ms$/),
|
||||
expect.stringMatching(/^b\.js .+ms$/),
|
||||
])
|
||||
);
|
||||
|
||||
// update timestamp
|
||||
const time = new Date();
|
||||
await fs.utimes(path.join(dir, "a.js"), time, time);
|
||||
|
||||
const { stdout: secondStdout } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--write",
|
||||
"--cache-strategy",
|
||||
"metadata",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(secondStdout).split("\n").filter(Boolean)).toEqual(
|
||||
// the cache of `b.js` is only available.
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/^a\.js .+ms$/),
|
||||
expect.stringMatching(/^b\.js .+ms \(cached\)$/),
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it("re-formats when options has been updated.", async () => {
|
||||
const { stdout: firstStdout } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--write",
|
||||
"--cache-strategy",
|
||||
"metadata",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(firstStdout).split("\n").filter(Boolean)).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/^a\.js .+ms$/),
|
||||
expect.stringMatching(/^b\.js .+ms$/),
|
||||
])
|
||||
);
|
||||
|
||||
const { stdout: secondStdout } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--cache-strategy",
|
||||
"metadata",
|
||||
"--write",
|
||||
"--trailing-comma",
|
||||
"all",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(secondStdout).split("\n").filter(Boolean)).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/^a\.js .+ms$/),
|
||||
expect.stringMatching(/^b\.js .+ms$/),
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it("removes cache file when run Prettier without `--cache` option", async () => {
|
||||
await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--write",
|
||||
"--cache-strategy",
|
||||
"metadata",
|
||||
".",
|
||||
]);
|
||||
await expect(fs.stat(defaultCacheFile)).resolves.not.toThrowError();
|
||||
await runPrettier(dir, ["--write", "."]);
|
||||
await expect(fs.stat(defaultCacheFile)).rejects.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe("--cache-strategy content", () => {
|
||||
it("creates default cache file named `node_modules/.cache/prettier/.prettier-cache`", async () => {
|
||||
await expect(fs.stat(defaultCacheFile)).rejects.toHaveProperty(
|
||||
"code",
|
||||
"ENOENT"
|
||||
);
|
||||
await runPrettier(dir, ["--cache", "--cache-strategy", "content", "."]);
|
||||
await expect(fs.stat(defaultCacheFile)).resolves.not.toThrowError();
|
||||
});
|
||||
|
||||
it("does'nt format when cache is available", async () => {
|
||||
const { stdout: firstStdout } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--cache-strategy",
|
||||
"content",
|
||||
"--write",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(firstStdout).split("\n").filter(Boolean)).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/^a\.js .+ms$/),
|
||||
expect.stringMatching(/^b\.js .+ms$/),
|
||||
])
|
||||
);
|
||||
|
||||
const { stdout: secondStdout } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--cache-strategy",
|
||||
"content",
|
||||
"--write",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(secondStdout).split("\n").filter(Boolean)).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/^a\.js .+ms \(cached\)$/),
|
||||
expect.stringMatching(/^b\.js .+ms \(cached\)$/),
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it("re-formats when a file has been updated.", async () => {
|
||||
const { stdout: firstStdout } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--cache-strategy",
|
||||
"content",
|
||||
"--write",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(firstStdout).split("\n").filter(Boolean)).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/^a\.js .+ms$/),
|
||||
expect.stringMatching(/^b\.js .+ms$/),
|
||||
])
|
||||
);
|
||||
|
||||
// Update `a.js`
|
||||
await fs.writeFile(path.join(dir, "a.js"), "const a = `a`;");
|
||||
|
||||
const { stdout: secondStdout } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--cache-strategy",
|
||||
"content",
|
||||
"--write",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(secondStdout).split("\n").filter(Boolean)).toEqual(
|
||||
// the cache of `b.js` is only available.
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/^a\.js .+ms$/),
|
||||
expect.stringMatching(/^b\.js .+ms \(cached\)$/),
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it("does'nt re-format when timestamp has been updated", async () => {
|
||||
const { stdout: firstStdout } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--cache-strategy",
|
||||
"content",
|
||||
"--write",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(firstStdout).split("\n").filter(Boolean)).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/^a\.js .+ms$/),
|
||||
expect.stringMatching(/^b\.js .+ms$/),
|
||||
])
|
||||
);
|
||||
|
||||
// update timestamp
|
||||
const time = new Date();
|
||||
await fs.utimes(path.join(dir, "a.js"), time, time);
|
||||
|
||||
const { stdout: secondStdout } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--cache-strategy",
|
||||
"content",
|
||||
"--write",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(secondStdout).split("\n").filter(Boolean)).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/^a\.js .+ms \(cached\)$/),
|
||||
expect.stringMatching(/^b\.js .+ms \(cached\)$/),
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it("re-formats when options has been updated.", async () => {
|
||||
const { stdout: firstStdout } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--cache-strategy",
|
||||
"content",
|
||||
"--write",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(firstStdout).split("\n").filter(Boolean)).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/^a\.js .+ms$/),
|
||||
expect.stringMatching(/^b\.js .+ms$/),
|
||||
])
|
||||
);
|
||||
|
||||
const { stdout: secondStdout } = await runPrettier(dir, [
|
||||
"--cache",
|
||||
"--write",
|
||||
"--cache-strategy",
|
||||
"content",
|
||||
"--trailing-comma",
|
||||
"all",
|
||||
".",
|
||||
]);
|
||||
expect(stripAnsi(secondStdout).split("\n").filter(Boolean)).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/^a\.js .+ms$/),
|
||||
expect.stringMatching(/^b\.js .+ms$/),
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it("removes cache file when run Prettier without `--cache` option", async () => {
|
||||
await runPrettier(dir, ["--cache", "--write", "."]);
|
||||
await expect(fs.stat(defaultCacheFile)).resolves.not.toThrowError();
|
||||
await runPrettier(dir, ["--write", "."]);
|
||||
await expect(fs.stat(defaultCacheFile)).rejects.toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
function a() {
|
||||
console.log("this is a.js")
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
function b() {
|
||||
console.log("this is b.js");
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"description": "this file is needed for testing to create default cache file"
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
// This file is generated automatically.
|
||||
export {default} from "sdbm";
|
||||
export * from "sdbm";
|
||||
Vendored
+35
@@ -0,0 +1,35 @@
|
||||
// @ts-nocheck
|
||||
// This file is generated automatically
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// node_modules/sdbm/index.js
|
||||
var sdbm_exports = {};
|
||||
__export(sdbm_exports, {
|
||||
default: () => sdbm
|
||||
});
|
||||
module.exports = __toCommonJS(sdbm_exports);
|
||||
function sdbm(string) {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < string.length; i++) {
|
||||
hash = string.charCodeAt(i) + (hash << 6) + (hash << 16) - hash;
|
||||
}
|
||||
return hash >>> 0;
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {});
|
||||
@@ -0,0 +1,531 @@
|
||||
---
|
||||
author: "Sosuke Suzuki (@sosukesuzuki)"
|
||||
authorURL: "https://github.com/sosukesuzuki"
|
||||
title: "Prettier 2.7: new --cache CLI option and TypeScript 4.7 syntax!"
|
||||
---
|
||||
|
||||
This release includes a new `--cache` CLI option. Enabling this option will use some attributes as cache keys and format files only if they have changed. This could dramatically improve CLI performance.
|
||||
|
||||
We've also added support formatting for TypeScript 4.7 syntax!
|
||||
|
||||
If you enjoy Prettier and would like to support our work, consider sponsoring us directly via [our OpenCollective](https://opencollective.com/prettier) or by sponsoring the projects we depend on, including [typescript-eslint](https://opencollective.com/typescript-eslint), [remark](https://opencollective.com/unified), and [Babel](https://opencollective.com/babel).
|
||||
|
||||
<!--truncate-->
|
||||
|
||||
## Highlights
|
||||
|
||||
### TypeScript
|
||||
|
||||
#### Support TypeScript 4.7 ([#12896](https://github.com/prettier/prettier/pull/12896), [#12897](https://github.com/prettier/prettier/pull/12897), [#12898](https://github.com/prettier/prettier/pull/12898), [#12900](https://github.com/prettier/prettier/pull/12900), [#12921](https://github.com/prettier/prettier/pull/12921), [#12924](https://github.com/prettier/prettier/pull/12924), [#12959](https://github.com/prettier/prettier/pull/12959) by [@sosukesuzuki](https://github.com/sosukesuzuki))
|
||||
|
||||
Support [TypeScript 4.7](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7) new features!
|
||||
|
||||
##### [Instantiation Expressions](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#instantiation-expressions)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```ts
|
||||
interface Box<T> {
|
||||
value: T;
|
||||
}
|
||||
function makeBox<T>(value: T) {
|
||||
return { value };
|
||||
}
|
||||
const makeHammerBox = makeBox<Hammer>;
|
||||
const makeWrenchBox = makeBox<Wrench>;
|
||||
```
|
||||
|
||||
##### [Optional Variance Annotations](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#optional-variance-annotations-for-type-parameters)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```ts
|
||||
interface Animal {
|
||||
animalStuff: any;
|
||||
}
|
||||
interface Dog extends Animal {
|
||||
dogStuff: any;
|
||||
}
|
||||
type Getter<out T> = () => T;
|
||||
type Setter<in T> = (value: T) => void;
|
||||
```
|
||||
|
||||
##### [`extends` constraints for `infer`](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#extends-constraints-on-infer-type-variables)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```ts
|
||||
type FirstString<T> = T extends [infer S extends string, ...unknown[]]
|
||||
? S
|
||||
: never;
|
||||
```
|
||||
|
||||
### CLI
|
||||
|
||||
#### Add `--cache` and `--cache-strategy` CLI options ([#12800](https://github.com/prettier/prettier/pull/12800) by [@sosukesuzuki](https://github.com/sosukesuzuki))
|
||||
|
||||
Two new CLI options have been added for a caching system similar to [ESLint's one](https://eslint.org/docs/user-guide/command-line-interface#caching).
|
||||
|
||||
Please see [the doc](https://prettier.io/docs/en/cli.html#--cache) for more details.
|
||||
|
||||
##### `--cache`
|
||||
|
||||
If this option is enabled, the following values are used as cache keys and the file is formatted only if one of them is changed.
|
||||
|
||||
- Prettier version
|
||||
- Options
|
||||
- Node.js version
|
||||
- (if `--cache-strategy` is `content`) content of the file
|
||||
- (if `--cache-strategy` is `metadata`) file metadata, such as timestamps
|
||||
|
||||
```bash
|
||||
prettier --write --cache src
|
||||
```
|
||||
|
||||
##### `--cache-strategy`
|
||||
|
||||
Strategy for the cache to use for detecting changed files. Can be either `metadata` or `content`. If no strategy is specified, `content` will be used.
|
||||
|
||||
```bash
|
||||
prettier --write --cache --cache-strategy metadata src
|
||||
```
|
||||
|
||||
## Other Changes
|
||||
|
||||
### JavaScript
|
||||
|
||||
#### Preserve blank line between export specifiers ([#12746](https://github.com/prettier/prettier/pull/12746) by [@sosukesuzuki](https://github.com/sosukesuzuki))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
// Input
|
||||
export {
|
||||
// a
|
||||
foo1,
|
||||
|
||||
// b
|
||||
bar1,
|
||||
baz1,
|
||||
} from "mod";
|
||||
|
||||
// Prettier 2.6
|
||||
export {
|
||||
// a
|
||||
foo1,
|
||||
// b
|
||||
bar1,
|
||||
baz1,
|
||||
} from "mod";
|
||||
|
||||
// Prettier 2.7
|
||||
export {
|
||||
// a
|
||||
foo1,
|
||||
|
||||
// b
|
||||
bar1,
|
||||
baz1,
|
||||
} from "mod";
|
||||
```
|
||||
|
||||
#### Make more callee patterns recognized as "test call callee". ([#12779](https://github.com/prettier/prettier/pull/12779) by [@HosokawaR](https://github.com/HosokawaR))
|
||||
|
||||
Supports test calls like [Playwright `test.describe`](https://playwright.dev/docs/api/class-test#test-describe).
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
// Input
|
||||
test.step("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe.only("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe.parallel("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe.parallel.only("does something really long and complicated so I have to write a very long name for the testThis is a very", () => {});
|
||||
|
||||
test.describe.serial("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe.serial.only("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
// Prettier 2.6
|
||||
test.step(
|
||||
"does something really long and complicated so I have to write a very long name for the test",
|
||||
() => {}
|
||||
);
|
||||
|
||||
test.describe(
|
||||
"does something really long and complicated so I have to write a very long name for the test",
|
||||
() => {}
|
||||
);
|
||||
|
||||
test.describe.only(
|
||||
"does something really long and complicated so I have to write a very long name for the test",
|
||||
() => {}
|
||||
);
|
||||
|
||||
test.describe.parallel(
|
||||
"does something really long and complicated so I have to write a very long name for the test",
|
||||
() => {}
|
||||
);
|
||||
|
||||
test.describe.parallel.only(
|
||||
"does something really long and complicated so I have to write a very long name for the testThis is a very",
|
||||
() => {}
|
||||
);
|
||||
|
||||
test.describe.serial(
|
||||
"does something really long and complicated so I have to write a very long name for the test",
|
||||
() => {}
|
||||
);
|
||||
|
||||
test.describe.serial.only(
|
||||
"does something really long and complicated so I have to write a very long name for the test",
|
||||
() => {}
|
||||
);
|
||||
|
||||
// Prettier 2.7
|
||||
test.step("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe
|
||||
.only("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe
|
||||
.parallel("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe.parallel
|
||||
.only("does something really long and complicated so I have to write a very long name for the testThis is a very", () => {});
|
||||
|
||||
test.describe
|
||||
.serial("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
|
||||
test.describe.serial
|
||||
.only("does something really long and complicated so I have to write a very long name for the test", () => {});
|
||||
```
|
||||
|
||||
#### Fix comment formats in ([#12860](https://github.com/prettier/prettier/pull/12860) by [@HosokawaR](https://github.com/HosokawaR))
|
||||
|
||||
This change fixes the comment format in `exports` to align with the comment format in `import`.
|
||||
|
||||
Although this change does not affect the comments format in `import`, follows change log contains examples of comments in `import` for reference.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
// Input
|
||||
export {
|
||||
foo,
|
||||
|
||||
bar as // comment
|
||||
baz,
|
||||
}
|
||||
|
||||
import {
|
||||
foo,
|
||||
|
||||
bar as // comment
|
||||
baz,
|
||||
} from 'foo'
|
||||
|
||||
// Prettier 2.6
|
||||
export {
|
||||
foo,
|
||||
bar as baz, // comment
|
||||
};
|
||||
|
||||
import {
|
||||
foo,
|
||||
// comment
|
||||
bar as baz,
|
||||
} from "foo";
|
||||
|
||||
// Prettier 2.7
|
||||
export {
|
||||
foo,
|
||||
// comment
|
||||
bar as baz,
|
||||
};
|
||||
|
||||
import {
|
||||
foo,
|
||||
// comment
|
||||
bar as baz,
|
||||
} from "foo";
|
||||
|
||||
```
|
||||
|
||||
### TypeScript
|
||||
|
||||
#### Print `as` instead of `:` for `babel-ts` parser ([#12706](https://github.com/prettier/prettier/pull/12706) by [@HosokawaR](https://github.com/HosokawaR))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```tsx
|
||||
// Input
|
||||
[x as any] = x;
|
||||
|
||||
// Prettier 2.6
|
||||
[x: any] = x;
|
||||
|
||||
// Prettier 2.7
|
||||
[x as any] = x;
|
||||
```
|
||||
|
||||
#### Fix formatting for typescript Enum with computed members ([#12930](https://github.com/prettier/prettier/pull/12930) by [@HosokawaR](https://github.com/HosokawaR))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```tsx
|
||||
// Input
|
||||
enum A {
|
||||
[i++],
|
||||
}
|
||||
|
||||
// Prettier 2.6
|
||||
enum A {
|
||||
i++,
|
||||
}
|
||||
|
||||
// Prettier 2.7
|
||||
enum A {
|
||||
[i++],
|
||||
}
|
||||
```
|
||||
|
||||
#### Stop parsing invalid code ([#12982](https://github.com/prettier/prettier/pull/12982) by [@fisker](https://github.com/fisker))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```tsx
|
||||
// Input
|
||||
const object = ({ methodName() });
|
||||
|
||||
// Prettier 2.6
|
||||
const object = { methodName(); };
|
||||
|
||||
// Prettier 2.7
|
||||
SyntaxError: Unexpected token. (1:29)
|
||||
> 1 | const object = ({ methodName() });
|
||||
| ^^
|
||||
```
|
||||
|
||||
### HTML
|
||||
|
||||
#### Support Speculation Rules API formatting in HTML ([#12882](https://github.com/prettier/prettier/pull/12882) by [@sosukesuzuki](https://github.com/sosukesuzuki))
|
||||
|
||||
Please read https://web.dev/speculative-prerendering/ for more information about the Speculation Rules API.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```html
|
||||
<!-- Input -->
|
||||
<script type="speculationrules">
|
||||
{
|
||||
"prerender": [
|
||||
{"source": "list", "urls": ["https://a.test/foo"]}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<!-- Prettier 2.6 -->
|
||||
<script type="speculationrules">
|
||||
{
|
||||
"prerender": [
|
||||
{"source": "list", "urls": ["https://a.test/foo"]}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Prettier 2.7 -->
|
||||
<script type="speculationrules">
|
||||
{
|
||||
"prerender": [{ "source": "list", "urls": ["https://a.test/foo"] }]
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### Vue
|
||||
|
||||
#### Allow formatting for Vue template expression written in TypeScript ([#12584](https://github.com/prettier/prettier/pull/12584) by [@sosukesuzuki](https://github.com/sosukesuzuki))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```vue
|
||||
<!-- input -->
|
||||
<script setup lang="ts">
|
||||
let x: string | number = 1
|
||||
</script>
|
||||
|
||||
<template>
|
||||
{{ (x as number).toFixed(2) }}
|
||||
</template>
|
||||
|
||||
<!-- Prettier 2.6 -->
|
||||
<script setup lang="ts">
|
||||
let x: string | number = 1
|
||||
</script>
|
||||
|
||||
<template>
|
||||
{{ (x as number).toFixed(2) }}
|
||||
</template>
|
||||
|
||||
<!-- Prettier 2.7 -->
|
||||
<script setup lang="ts">
|
||||
let x: string | number = 1;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
{{ (x as number).toFixed(2) }}
|
||||
</template>
|
||||
```
|
||||
|
||||
#### Infer Stylus parser for Vue SFC style block ([#12707](https://github.com/prettier/prettier/pull/12707) by [@lsdsjy](https://github.com/lsdsjy))
|
||||
|
||||
`<style lang="stylus">` blocks in Vue SFCs can be processed by the appropriate plugin if any.
|
||||
|
||||
#### Avoid printing attribute per line in Vue SFC blocks ([#12895](https://github.com/prettier/prettier/pull/12895) by [@sosukesuzuki](https://github.com/sosukesuzuki))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```vue
|
||||
<!-- Input (singleAttributePerLine: true) -->
|
||||
<script lang="ts" setup>
|
||||
</script>
|
||||
|
||||
<!-- Prettier 2.6 -->
|
||||
<script
|
||||
lang="ts"
|
||||
setup
|
||||
>
|
||||
</script>
|
||||
|
||||
<!-- Prettier 2.7 -->
|
||||
<script lang="ts" setup>
|
||||
</script>
|
||||
```
|
||||
|
||||
### Angular
|
||||
|
||||
#### Fix shorthand properties formatting ([#12993](https://github.com/prettier/prettier/pull/12993) by [@sosukesuzuki](https://github.com/sosukesuzuki), [@fisker](https://github.com/fisker))
|
||||
|
||||
```html
|
||||
<!-- Input -->
|
||||
<ng-container *ngTemplateOutlet="someTmpl; context: { app }"></ng-container>
|
||||
|
||||
<!-- Prettier 2.6 -->
|
||||
<ng-container
|
||||
*ngTemplateOutlet="someTmpl; context: { app: this.app }"
|
||||
></ng-container>
|
||||
|
||||
<!-- Prettier 2.7 -->
|
||||
<ng-container *ngTemplateOutlet="someTmpl; context: { app }"></ng-container>
|
||||
```
|
||||
|
||||
### GraphQL
|
||||
|
||||
#### Add support for printing SchemaExtension nodes ([#12519](https://github.com/prettier/prettier/pull/12519) by [@trevor-scheer](https://github.com/trevor-scheer))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```graphql
|
||||
# Input
|
||||
extend schema { subscription: Subscription }
|
||||
extend schema @directive
|
||||
|
||||
# Prettier 2.6
|
||||
N/A - throws error
|
||||
|
||||
# Prettier 2.7
|
||||
extend schema {
|
||||
subscription: Subscription
|
||||
}
|
||||
extend schema @directive
|
||||
```
|
||||
|
||||
#### Fix single line and empty description formatting ([#12608](https://github.com/prettier/prettier/pull/12608) by [@chimurai](https://github.com/chimurai), [@fisker](https://github.com/fisker))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```graphql
|
||||
# Input
|
||||
""" Customer """
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
""""""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
# Prettier 2.6.2
|
||||
"""
|
||||
Customer
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
# Prettier 2.6.2 (second format)
|
||||
"""
|
||||
Customer
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
# Prettier 2.7
|
||||
"""
|
||||
Customer
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
|
||||
"""
|
||||
"""
|
||||
type Person {
|
||||
name: String
|
||||
}
|
||||
```
|
||||
|
||||
### CLI
|
||||
|
||||
#### Print the number of files need change ([#12561](https://github.com/prettier/prettier/pull/12561) by [@Harry-Hopkinson](https://github.com/Harry-Hopkinson))
|
||||
|
||||
```console
|
||||
# Prettier 2.6
|
||||
$ prettier src --check
|
||||
Checking formatting...
|
||||
[warn] src/fileA.js
|
||||
[warn] Code style issues found in the above file(s). Forgot to run Prettier?
|
||||
|
||||
# Prettier 2.7
|
||||
$ prettier src --check
|
||||
Checking formatting...
|
||||
[warn] src/fileA.js
|
||||
[warn] src/fileB.js
|
||||
[warn] Code style issues found in 2 files. Forgot to run Prettier?
|
||||
|
||||
$ prettier src --check
|
||||
Checking formatting...
|
||||
[warn] src/fileA.js
|
||||
[warn] Code style issues found in the above file. Forgot to run Prettier?
|
||||
```
|
||||
|
||||
#### Infer parser for `.importmap` files ([#12603](https://github.com/prettier/prettier/pull/12603) by [@fisker](https://github.com/fisker))
|
||||
|
||||
Format [`.importmap`](https://github.com/WICG/import-maps#import-map-processing) files as JSON files.
|
||||
|
||||
#### Simplify performance test ([#12682](https://github.com/prettier/prettier/pull/12682), [#12698](https://github.com/prettier/prettier/pull/12698) by [@fisker](https://github.com/fisker))
|
||||
|
||||
When `--debug-benchmark` or `--debug-repeat` is passed:
|
||||
|
||||
1. The CLI skips print code to the screen or write file
|
||||
1. Set log level to `debug` automatically
|
||||
@@ -320,7 +320,7 @@ const UsersSection = ({ language }) => {
|
||||
<div style={{ marginLeft: ".7em", width: "260px" }}>
|
||||
<p>
|
||||
More than{" "}
|
||||
<strong data-placeholder="dependent-github">4 million</strong>{" "}
|
||||
<strong data-placeholder="dependent-github">4.3 million</strong>{" "}
|
||||
dependent repositories on GitHub
|
||||
</p>
|
||||
<Button href="https://github.com/prettier/prettier/network/dependents">
|
||||
@@ -336,7 +336,7 @@ const UsersSection = ({ language }) => {
|
||||
<div style={{ marginLeft: ".7em", width: "260px" }}>
|
||||
<p>
|
||||
More than{" "}
|
||||
<strong data-placeholder="dependent-npm">10.6k</strong>{" "}
|
||||
<strong data-placeholder="dependent-npm">11.3k</strong>{" "}
|
||||
dependent packages on npm
|
||||
</p>
|
||||
<Button href="https://www.npmjs.com/browse/depended/prettier">
|
||||
|
||||
@@ -94,3 +94,27 @@ export function getAstAutoFold(parser) {
|
||||
return astAutoFold.glimmer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied from https://github.com/prettier/prettier/blob/6fe21780115cf5f74f83876d64b03a727fbab220/src/cli/utils.js#L6-L27
|
||||
* @template Obj
|
||||
* @template Key
|
||||
* @param {Array<Obj>} array
|
||||
* @param {(value: Obj) => Key} iteratee
|
||||
* @returns {{[p in Key]: T}}
|
||||
*/
|
||||
export function groupBy(array, iteratee) {
|
||||
const result = Object.create(null);
|
||||
|
||||
for (const value of array) {
|
||||
const key = iteratee(value);
|
||||
|
||||
if (Array.isArray(result[key])) {
|
||||
result[key].push(value);
|
||||
} else {
|
||||
result[key] = [value];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -116,20 +116,20 @@ The support information looks like this:
|
||||
```typescript
|
||||
{
|
||||
languages: Array<{
|
||||
name: string,
|
||||
since?: string,
|
||||
parsers: string[],
|
||||
group?: string,
|
||||
tmScope?: string,
|
||||
aceMode?: string,
|
||||
codemirrorMode?: string,
|
||||
codemirrorMimeType?: string,
|
||||
aliases?: string[],
|
||||
extensions?: string[],
|
||||
filenames?: string[],
|
||||
linguistLanguageId?: number,
|
||||
vscodeLanguageIds?: string[],
|
||||
}>
|
||||
name: string;
|
||||
since?: string;
|
||||
parsers: string[];
|
||||
group?: string;
|
||||
tmScope?: string;
|
||||
aceMode?: string;
|
||||
codemirrorMode?: string;
|
||||
codemirrorMimeType?: string;
|
||||
aliases?: string[];
|
||||
extensions?: string[];
|
||||
filenames?: string[];
|
||||
linguistLanguageId?: number;
|
||||
vscodeLanguageIds?: string[];
|
||||
}>;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ See below for examples.
|
||||
### Global
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/prettier@2.6.2/standalone.js"></script>
|
||||
<script src="https://unpkg.com/prettier@2.6.2/parser-graphql.js"></script>
|
||||
<script src="https://unpkg.com/prettier@2.7.1/standalone.js"></script>
|
||||
<script src="https://unpkg.com/prettier@2.7.1/parser-graphql.js"></script>
|
||||
<script>
|
||||
prettier.format("type Query { hello: String }", {
|
||||
parser: "graphql",
|
||||
@@ -49,8 +49,8 @@ Note that the [`unpkg` field](https://unpkg.com/#examples) in Prettier’s `pack
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import prettier from "https://unpkg.com/prettier@2.6.2/esm/standalone.mjs";
|
||||
import parserGraphql from "https://unpkg.com/prettier@2.6.2/esm/parser-graphql.mjs";
|
||||
import prettier from "https://unpkg.com/prettier@2.7.1/esm/standalone.mjs";
|
||||
import parserGraphql from "https://unpkg.com/prettier@2.7.1/esm/parser-graphql.mjs";
|
||||
|
||||
prettier.format("type Query { hello: String }", {
|
||||
parser: "graphql",
|
||||
@@ -63,8 +63,8 @@ Note that the [`unpkg` field](https://unpkg.com/#examples) in Prettier’s `pack
|
||||
|
||||
```js
|
||||
define([
|
||||
"https://unpkg.com/prettier@2.6.2/standalone.js",
|
||||
"https://unpkg.com/prettier@2.6.2/parser-graphql.js",
|
||||
"https://unpkg.com/prettier@2.7.1/standalone.js",
|
||||
"https://unpkg.com/prettier@2.7.1/parser-graphql.js",
|
||||
], (prettier, ...plugins) => {
|
||||
prettier.format("type Query { hello: String }", {
|
||||
parser: "graphql",
|
||||
@@ -89,8 +89,8 @@ This syntax doesn’t necessarily work in the browser, but it can be used when b
|
||||
### Worker
|
||||
|
||||
```js
|
||||
importScripts("https://unpkg.com/prettier@2.6.2/standalone.js");
|
||||
importScripts("https://unpkg.com/prettier@2.6.2/parser-graphql.js");
|
||||
importScripts("https://unpkg.com/prettier@2.7.1/standalone.js");
|
||||
importScripts("https://unpkg.com/prettier@2.7.1/parser-graphql.js");
|
||||
prettier.format("type Query { hello: String }", {
|
||||
parser: "graphql",
|
||||
plugins: prettierPlugins,
|
||||
@@ -103,8 +103,8 @@ If you want to format [embedded code](options.md#embedded-language-formatting),
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import prettier from "https://unpkg.com/prettier@2.6.2/esm/standalone.mjs";
|
||||
import parserBabel from "https://unpkg.com/prettier@2.6.2/esm/parser-babel.mjs";
|
||||
import prettier from "https://unpkg.com/prettier@2.7.1/esm/standalone.mjs";
|
||||
import parserBabel from "https://unpkg.com/prettier@2.7.1/esm/parser-babel.mjs";
|
||||
|
||||
console.log(
|
||||
prettier.format("const html=/* HTML */ `<DIV> </DIV>`", {
|
||||
@@ -120,9 +120,9 @@ The HTML code embedded in JavaScript stays unformatted because the `html` parser
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import prettier from "https://unpkg.com/prettier@2.6.2/esm/standalone.mjs";
|
||||
import parserBabel from "https://unpkg.com/prettier@2.6.2/esm/parser-babel.mjs";
|
||||
import parserHtml from "https://unpkg.com/prettier@2.6.2/esm/parser-html.mjs";
|
||||
import prettier from "https://unpkg.com/prettier@2.7.1/esm/standalone.mjs";
|
||||
import parserBabel from "https://unpkg.com/prettier@2.7.1/esm/parser-babel.mjs";
|
||||
import parserHtml from "https://unpkg.com/prettier@2.7.1/esm/parser-html.mjs";
|
||||
|
||||
console.log(
|
||||
prettier.format("const html=/* HTML */ `<DIV> </DIV>`", {
|
||||
|
||||
@@ -205,3 +205,35 @@ Prevent errors when pattern is unmatched.
|
||||
## `--no-plugin-search`
|
||||
|
||||
Disable plugin autoloading.
|
||||
|
||||
## `--cache`
|
||||
|
||||
If this option is enabled, the following values are used as cache keys and the file is formatted only if one of them is changed.
|
||||
|
||||
- Prettier version
|
||||
- Options
|
||||
- Node.js version
|
||||
- (if `--cache-strategy` is `metadata`) file metadata, such as timestamps
|
||||
- (if `--cache-strategy` is `content`) content of the file
|
||||
|
||||
```bash
|
||||
prettier --write --cache src
|
||||
```
|
||||
|
||||
Running Prettier without `--cache` will delete the cache.
|
||||
|
||||
Also, since the cache file is stored in `./node_modules/.cache/prettier/.prettier-cache`, so you can use `rm ./node_modules/.cache/prettier/.prettier-cache` to remove it manually.
|
||||
|
||||
> Plugins version and implementation are not used as cache keys. We recommend that you delete the cache when updating plugins.
|
||||
|
||||
## `--cache-strategy`
|
||||
|
||||
Strategy for the cache to use for detecting changed files. Can be either `metadata` or `content`.
|
||||
|
||||
In general, `metadata` is faster. However, `content` is useful for updating the timestamp without changing the file content. This can happen, for example, during git operations such as `git clone`, because it does not track file modification times.
|
||||
|
||||
If no strategy is specified, `content` will be used.
|
||||
|
||||
```bash
|
||||
prettier --write --cache --cache-strategy metadata src
|
||||
```
|
||||
@@ -177,9 +177,37 @@ If you’d like a JSON schema to validate your configuration, one is available h
|
||||
|
||||
## EditorConfig
|
||||
|
||||
If `options.editorconfig` is `true` and an [`.editorconfig` file](https://editorconfig.org/) is in your project, Prettier will parse it and convert its properties to the corresponding Prettier configuration. This configuration will be overridden by `.prettierrc`, etc. Currently, the following EditorConfig properties are supported:
|
||||
If `options.editorconfig` is `true` and an [`.editorconfig` file](https://editorconfig.org/) is in your project, Prettier will parse it and convert its properties to the corresponding Prettier configuration. This configuration will be overridden by `.prettierrc`, etc.
|
||||
|
||||
- `end_of_line`
|
||||
- `indent_style`
|
||||
- `indent_size`/`tab_width`
|
||||
- `max_line_length`
|
||||
Here’s an annotated description of how different properties map to Prettier’s behavior:
|
||||
|
||||
```ini
|
||||
# Stop the editor from looking for .editorconfig files in the parent directories
|
||||
# root = true
|
||||
|
||||
[*]
|
||||
# Non-configurable Prettier behaviors
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
# Caveat: Prettier won’t trim trailing whitespace inside template strings, but your editor might.
|
||||
# trim_trailing_whitespace = true
|
||||
|
||||
# Configurable Prettier behaviors
|
||||
# (change these if your Prettier config differs)
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
max_line_length = 80
|
||||
```
|
||||
|
||||
Here’s a copy+paste-ready `.editorconfig` file if you use the default options:
|
||||
|
||||
```ini
|
||||
[*]
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
max_line_length = 80
|
||||
```
|
||||
@@ -61,6 +61,7 @@ To turn off plugin autoloading, use `--no-plugin-search` when using Prettier CLI
|
||||
- [`prettier-plugin-apex`](https://github.com/dangmai/prettier-plugin-apex) by [**@dangmai**](https://github.com/dangmai)
|
||||
- [`prettier-plugin-elm`](https://github.com/gicentre/prettier-plugin-elm) by [**@giCentre**](https://github.com/gicentre)
|
||||
- [`prettier-plugin-erb`](https://github.com/adamzapasnik/prettier-plugin-erb) by [**@adamzapasnik**](https://github.com/adamzapasnik)
|
||||
- [`prettier-plugin-glsl`](https://github.com/NaridaL/glsl-language-toolkit/tree/main/packages/prettier-plugin-glsl) by [**@NaridaL**](https://github.com/NaridaL)
|
||||
- [`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-jsonata`](https://github.com/Stedi/prettier-plugin-jsonata) by [**@Stedi**](https://github.com/Stedi)
|
||||
|
||||
Reference in new issue
Block a user