3.2 blog post (#15892)
Co-authored-by: Alexander Kachkaev <alexander@kachkaev.ru>
This commit is contained in:
1 parent
9219c130ce
commit
1890d55900
2 files changed
+402
No files matched your search
@@ -0,0 +1,15 @@
|
||||
---
|
||||
author: "Sosuke Suzuki (@sosukesuzuki)"
|
||||
authorURL: "https://github.com/sosukesuzuki"
|
||||
title: "Prettier 3.2: Support JSONC and Angular’s ICU expression"
|
||||
---
|
||||
|
||||
This release includes new features such as adding a JSONC parser, adding Angular’s ICU expressions, and many bug fixes.
|
||||
|
||||
We are still seeking feedback for the `--experimental-ternaries` option released in Prettier 3.1. Please read [A curious case of the ternaries](https://prettier.io/blog/2023/11/13/curious-ternaries) and respond via the Google Forms link provided.
|
||||
|
||||
Additionally, we recommend reading [Prettier's CLI: A Performance Deep Dive](https://prettier.io/blog/2023/11/30/cli-deep-dive) by [Fabio Spampinato](https://github.com/fabiospampinato). This faster CLI is slated to be released as version 4.0.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
If you appreciate Prettier and would like to support our work, please consider sponsoring us directly via [our OpenCollective](https://opencollective.com/prettier) or by sponsoring the projects we depend on, such as [typescript-eslint](https://opencollective.com/typescript-eslint), [remark](https://opencollective.com/unified), and [Babel](https://opencollective.com/babel). Thank you for your continued support!
|
||||
@@ -0,0 +1,387 @@
|
||||
---
|
||||
author: "Sosuke Suzuki (@sosukesuzuki)"
|
||||
authorURL: "https://github.com/sosukesuzuki"
|
||||
title: "Prettier 3.2: Support JSONC and Angular’s ICU expression"
|
||||
---
|
||||
|
||||
This release includes new features such as adding a JSONC parser, adding Angular’s ICU expressions, and many bug fixes.
|
||||
|
||||
We are still seeking feedback for the `--experimental-ternaries` option released in Prettier 3.1. Please read [A curious case of the ternaries](https://prettier.io/blog/2023/11/13/curious-ternaries) and respond via the Google Forms link provided.
|
||||
|
||||
Additionally, we recommend reading [Prettier's CLI: A Performance Deep Dive](https://prettier.io/blog/2023/11/30/cli-deep-dive) by [Fabio Spampinato](https://github.com/fabiospampinato). This faster CLI is slated to be released as version 4.0.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
If you appreciate Prettier and would like to support our work, please consider sponsoring us directly via [our OpenCollective](https://opencollective.com/prettier) or by sponsoring the projects we depend on, such as [typescript-eslint](https://opencollective.com/typescript-eslint), [remark](https://opencollective.com/unified), and [Babel](https://opencollective.com/babel). Thank you for your continued support!
|
||||
|
||||
## Highlights
|
||||
|
||||
### JSON
|
||||
|
||||
#### New `jsonc` parser added ([#15831](https://github.com/prettier/prettier/pull/15831) by [@fisker](https://github.com/fisker))
|
||||
|
||||
Previously, we infer the parser of `.jsonc` files to be `json`, but if we want keep the trailing comma, we'll have to use a hacky workaround config `{parser: "json5", quoteProps: "preserve", singleQuote: false}`.
|
||||
|
||||
The new added `jsonc` parser:
|
||||
|
||||
- Always quote the object keys.
|
||||
- Wrap strings with double quotes.
|
||||
- Of course, respect the [`trailingComma`](https://prettier.io/docs/en/options#trailing-commas) option.
|
||||
|
||||
### Angular
|
||||
|
||||
#### Support formatting for Angular ICU expression ([#15777](https://github.com/prettier/prettier/pull/15777) by [@sosukesuzuki](https://github.com/sosukesuzuki))
|
||||
|
||||
Support two kinds of Angular ICU expressions: [`plural`](https://angular.dev/guide/i18n/translation-files#translate-plurals) and [`select`](https://angular.dev/guide/i18n/translation-files#translate-alternate-expressions).
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```html
|
||||
<span i18n>
|
||||
Updated:
|
||||
{minutes, plural,
|
||||
=0 {just now}
|
||||
=1 {one minute ago}
|
||||
other {{{minutes}} minutes ago}
|
||||
}
|
||||
</span>
|
||||
|
||||
<span i18n>
|
||||
The author is {gender, select, male {male} female {female} other {other}}
|
||||
</span>
|
||||
```
|
||||
|
||||
## Other Changes
|
||||
|
||||
### JavaScript
|
||||
|
||||
#### Avoid introducing linebreaks in template interpolations ([#15209](https://github.com/prettier/prettier/pull/15209) by [@bakkot](https://github.com/bakkot))
|
||||
|
||||
In a template string like
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
`this is a long message which contains an interpolation: ${format(data)} <- like this`;
|
||||
```
|
||||
|
||||
avoid adding a linebreak when formatting the expression unless one is already present or it's unavoidable due to e.g. a nested function. Previously a linebreak could be introduced whenever some interpolation in the template was sufficiently "not simple":
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
`this is a long message which contains an interpolation: ${format(
|
||||
data,
|
||||
)} <- like this`;
|
||||
```
|
||||
|
||||
Now it will instead be left alone.
|
||||
|
||||
If a linebreak is already present within the `${...}`, format as normal.
|
||||
|
||||
#### Fix non-idempotent formatting of method chain with empty line ([#15522](https://github.com/prettier/prettier/pull/15522) by [@seiyab](https://github.com/seiyab))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
// Input
|
||||
Foo.a()
|
||||
|
||||
.b();
|
||||
|
||||
// Prettier 3.1 (first format)
|
||||
Foo.a()
|
||||
.b();
|
||||
|
||||
// Prettier 3.1 (second format)
|
||||
Foo.a().b();
|
||||
|
||||
|
||||
// Prettier 3.2
|
||||
Foo.a()
|
||||
|
||||
.b();
|
||||
```
|
||||
|
||||
#### Fix formatting of ternary in function call ([#15677](https://github.com/prettier/prettier/pull/15677) by [@fisker](https://github.com/fisker))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
// Input
|
||||
stopDirectory = await (useCache
|
||||
? memoizedFindProjectRoot
|
||||
: findProjectRootWithoutCache)(path.dirname(path.resolve(filePath)));
|
||||
|
||||
// Prettier 3.1
|
||||
stopDirectory = await (useCache
|
||||
? memoizedFindProjectRoot
|
||||
: findProjectRootWithoutCache)(path.dirname(path.resolve(filePath)));
|
||||
|
||||
// Prettier 3.2
|
||||
stopDirectory = await (
|
||||
useCache ? memoizedFindProjectRoot : findProjectRootWithoutCache
|
||||
)(path.dirname(path.resolve(filePath)));
|
||||
```
|
||||
|
||||
#### Fix inconsistencies for optional-chaining ([#15806](https://github.com/prettier/prettier/pull/15806) by [@fisker](https://github.com/fisker))
|
||||
|
||||
Only happens when using `typescript`, `meriyah` or other ESTree parsers except `babel`.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
// Input
|
||||
function someFunctionName() {
|
||||
return isEqual(a.map(([t, _]) => t?.id), b.map(([t, _]) => t?.id));
|
||||
return isEqual(a?.map(([t, _]) => t?.id), b?.map(([t, _]) => t?.id));
|
||||
}
|
||||
theValue = Object.entries(someLongObjectName).filter(
|
||||
([listingId]) => someListToCompareToHere.includes(listingId),
|
||||
);
|
||||
theValue = Object.entries(someLongObjectName).filter(
|
||||
([listingId]) => someListToCompareToHere?.includes(listingId),
|
||||
);
|
||||
|
||||
// Prettier 3.1
|
||||
function someFunctionName() {
|
||||
return isEqual(
|
||||
a.map(([t, _]) => t?.id),
|
||||
b.map(([t, _]) => t?.id),
|
||||
);
|
||||
return isEqual(a?.map(([t, _]) => t?.id), b?.map(([t, _]) => t?.id));
|
||||
}
|
||||
theValue = Object.entries(someLongObjectName).filter(([listingId]) =>
|
||||
someListToCompareToHere.includes(listingId),
|
||||
);
|
||||
theValue = Object.entries(someLongObjectName).filter(
|
||||
([listingId]) => someListToCompareToHere?.includes(listingId),
|
||||
);
|
||||
|
||||
// Prettier 3.2
|
||||
function someFunctionName() {
|
||||
return isEqual(
|
||||
a.map(([t, _]) => t?.id),
|
||||
b.map(([t, _]) => t?.id),
|
||||
);
|
||||
return isEqual(
|
||||
a?.map(([t, _]) => t?.id),
|
||||
b?.map(([t, _]) => t?.id),
|
||||
);
|
||||
}
|
||||
theValue = Object.entries(someLongObjectName).filter(([listingId]) =>
|
||||
someListToCompareToHere.includes(listingId),
|
||||
);
|
||||
theValue = Object.entries(someLongObjectName).filter(([listingId]) =>
|
||||
someListToCompareToHere?.includes(listingId),
|
||||
);
|
||||
```
|
||||
|
||||
#### Fix comments in `if` ([#15826](https://github.com/prettier/prettier/pull/15826) by [@fisker](https://github.com/fisker))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
// Input
|
||||
if (foo) for (i = 2; i > 0; i--) console.log(i); // comment 1
|
||||
else bar();
|
||||
|
||||
for (;;){
|
||||
if (foo) continue; // comment 2
|
||||
else bar();
|
||||
}
|
||||
|
||||
// Prettier 3.1
|
||||
Error: Comment "comment 2" was not printed. Please report this error!
|
||||
|
||||
// Prettier 3.2
|
||||
if (foo)
|
||||
for (i = 2; i > 0; i--) console.log(i); // comment 1
|
||||
else bar();
|
||||
|
||||
for (;;) {
|
||||
if (foo)
|
||||
continue; // comment 2
|
||||
else bar();
|
||||
}
|
||||
```
|
||||
|
||||
### TypeScript
|
||||
|
||||
#### Improve conditional type alias layout ([#15811](https://github.com/prettier/prettier/pull/15811) by [@seiyab](https://github.com/seiyab))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```ts
|
||||
// Input
|
||||
type FallbackFlags<F extends Flags | undefined> =
|
||||
Equals<NonNullableFlag<F>["flags"], {}> extends true
|
||||
? Dict<any>
|
||||
: NonNullableFlag<F>["flags"];
|
||||
|
||||
// Prettier 3.1
|
||||
type FallbackFlags<F extends Flags | undefined> = Equals<
|
||||
NonNullableFlag<F>["flags"],
|
||||
{}
|
||||
> extends true
|
||||
? Dict<any>
|
||||
: NonNullableFlag<F>["flags"];
|
||||
|
||||
// Prettier 3.2
|
||||
type FallbackFlags<F extends Flags | undefined> =
|
||||
Equals<NonNullableFlag<F>["flags"], {}> extends true
|
||||
? Dict<any>
|
||||
: NonNullableFlag<F>["flags"];
|
||||
```
|
||||
|
||||
### HTML
|
||||
|
||||
#### Fix formatting of prettier-ignored unclosed elements ([#15748](https://github.com/prettier/prettier/pull/15748) by [@fisker](https://github.com/fisker))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```html
|
||||
<!-- Input -->
|
||||
<!-- prettier-ignore -->
|
||||
<h1>
|
||||
Hello <span>world!
|
||||
|
||||
<!-- Prettier 3.1 -->
|
||||
<!-- prettier-ignore -->
|
||||
<h1>
|
||||
|
||||
<!-- Prettier 3.2 -->
|
||||
<!-- prettier-ignore -->
|
||||
<h1>
|
||||
Hello <span>world!
|
||||
```
|
||||
|
||||
### Angular
|
||||
|
||||
#### Fix `prettier-ignore`d angular control flow block ([#15827](https://github.com/prettier/prettier/pull/15827) by [@fisker](https://github.com/fisker))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```html
|
||||
<!-- Input -->
|
||||
<!-- prettier-ignore -->
|
||||
@if (condition) {
|
||||
Foo
|
||||
} @else {
|
||||
Other
|
||||
}
|
||||
|
||||
<!-- Prettier 3.1 -->
|
||||
<!-- prettier-ignore -->
|
||||
@if (condition) {
|
||||
Foo
|
||||
}
|
||||
} @else {
|
||||
Other
|
||||
}
|
||||
|
||||
<!-- Prettier 3.2 -->
|
||||
<!-- prettier-ignore -->
|
||||
@if (condition) {
|
||||
Foo
|
||||
}
|
||||
@else {
|
||||
Other
|
||||
}
|
||||
```
|
||||
|
||||
#### Avoid adding colon for `track` in 3rd expression of `for` blocks ([#15887](https://github.com/prettier/prettier/pull/15887) by [@sosukesuzuki](https://github.com/sosukesuzuki))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```html
|
||||
<!-- Input -->
|
||||
@for (item of items; let i = $index; track block) {}
|
||||
|
||||
<!-- Prettier 3.1 -->
|
||||
@for (item of items; let i = $index; track: block) {}
|
||||
|
||||
<!-- Prettier 3.2 -->
|
||||
@for (item of items; let i = $index; track block) {}
|
||||
```
|
||||
|
||||
### Ember / Handlebars
|
||||
|
||||
#### Preserve path literal segments ([#15605](https://github.com/prettier/prettier/pull/15605) by [@maxpowa](https://github.com/maxpowa))
|
||||
|
||||
Fixes scenarios where an input handlebars file containing literal segments would be reformatted to unwrap the literal segments, causing syntax errors in the resulting output.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```hbs
|
||||
<!-- Input -->
|
||||
{{input.[funky<api!response]}}
|
||||
{{input.[this one has spaces]}}
|
||||
{{input.[anotherone].[0]}}
|
||||
|
||||
<!-- Prettier 3.1 -->
|
||||
{{input.funky<api!response}}
|
||||
{{input.this one has spaces}}
|
||||
{{input.anotherone.0}}
|
||||
|
||||
<!-- Prettier 3.2 -->
|
||||
{{input.[funky<api!response]}}
|
||||
{{input.[this one has spaces]}}
|
||||
{{input.anotherone.[0]}}
|
||||
```
|
||||
|
||||
### GraphQL
|
||||
|
||||
#### Improve GraphQL union types formatting ([#15870](https://github.com/prettier/prettier/pull/15870) by [@ArchitGajjar](https://github.com/ArchitGajjar))
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```gql
|
||||
# Input
|
||||
union SearchResult = Conference| Festival | Concert | Venue | Conference| Festival | Concert | Venue
|
||||
|
||||
# Prettier 3.1
|
||||
union SearchResult =
|
||||
Conference
|
||||
| Festival
|
||||
| Concert
|
||||
| Venue
|
||||
| Conference
|
||||
| Festival
|
||||
| Concert
|
||||
| Venue
|
||||
|
||||
# Prettier 3.2
|
||||
union SearchResult =
|
||||
| Conference
|
||||
| Festival
|
||||
| Concert
|
||||
| Venue
|
||||
| Conference
|
||||
| Festival
|
||||
| Concert
|
||||
| Venue
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
#### Support absolute path as plugin in config file ([#15666](https://github.com/prettier/prettier/pull/15666) by [@fisker](https://github.com/fisker))
|
||||
|
||||
```js
|
||||
// prettier.config.cjs
|
||||
module.exports = {
|
||||
plugins: [
|
||||
// posix style
|
||||
"/path/to/plugin.js",
|
||||
// Windows style
|
||||
"D:\\\\path\\to\\plugin.js",
|
||||
// Use `require.resolve`
|
||||
require.resolve("my-awesome-prettier-plugin"),
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
#### Fix `getFileInfo` and `getSupportInfo` type definitions ([#15854](https://github.com/prettier/prettier/pull/15854) by [@auvred](https://github.com/auvred))
|
||||
|
||||
```ts
|
||||
const plugin: Plugin = {};
|
||||
|
||||
prettier.getFileInfo("./file.ext", {
|
||||
plugins: [plugin],
|
||||
});
|
||||
|
||||
prettier.getSupportInfo({ plugins: [plugin], showDeprecated: true });
|
||||
```
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
#### Fix false claim in docs that cursorOffset is incompatible with rangeStart/rangeEnd ([#15750](https://github.com/prettier/prettier/pull/15750) by [@ExplodingCabbage](https://github.com/ExplodingCabbage))
|
||||
|
||||
The cursorOffset option has in fact been compatible with rangeStart/rangeEnd for over 5 years, thanks to work by @ds300. However, Prettier's documentation (including the CLI `--help` text) continued to claim otherwise, falsely. The documentation is now fixed.
|
||||
Reference in new issue
Block a user