Skip to content

breaking: new options, deprecate svelteStrictMode #380

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

- (breaking) requires `prettier` version 3
- (breaking) requires node version 14 or higher
- (breaking) Whether or not empty elements/components should self-close is now left to the user - in other words, if you write `<div />` or `<Component />` that stays as is, and so does `<div></div>`/`<Component></Component>`. If `svelteStrictMode` is turned on, it will still only allow `<div></div>` notation for elements (but it will leave your components alone)
- (breaking) `svelteAllowShorthand` now takes precedence over `svelteStrictMode`, which no longer has any effect on that behavior. Set `svelteAllowShorthand` to `false` to get back the v2 behavior

## 2.10.1

Expand Down
77 changes: 62 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ Install `prettier` and `prettier-plugin-svelte` as dev dependencies in your proj
Then format your code using Prettier CLI. You may need to add `--plugin-search-dir=.`

As a one-time run:

```
npx prettier --write --plugin-search-dir=. ./**/*.html
```

As part of your scripts in `package.json`:

```
"format": "prettier --write --plugin-search-dir=. ./**/*.html"
```
Expand All @@ -43,7 +45,7 @@ If you want to customize some formatting behavior, see section "Options" below.

## Options

``Configurations are optional``
`Configurations are optional`

Make a `.prettierrc` file in your project directory and add your preferred [options](https://prettier.io/docs/en/options.html) to [configure Prettier](https://prettier.io/docs/en/configuration.html). When using Prettier through the CLI, you can also pass options through CLI flags, but a `.prettierrc` file is recommended.

Expand All @@ -61,10 +63,13 @@ Format: join the keywords `options`, `scripts`, `markup`, `styles` with a `-` in

### Svelte Strict Mode

More strict HTML syntax: less self-closed tags, quotes in attributes, no attribute shorthand (overrules `svelteAllowShorthand`).
More strict HTML syntax: Quotes in attributes and no self-closing DOM elements (except void elements).

> In version 2 this overruled `svelteAllowShorthand`, which is no longer the case.

Example:

<!-- prettier-ignore -->
```html
<!-- svelteStrictMode: true -->
<div foo="{bar}"></div>
Expand All @@ -83,6 +88,7 @@ Option to enable/disable component attribute shorthand if attribute name and exp

Example:

<!-- prettier-ignore -->
```html
<!-- allowShorthand: true -->
<input type="text" {value} />
Expand All @@ -95,6 +101,44 @@ Example:
| ------- | --------------------------------- | ------------------------------ |
| `true` | `--svelte-allow-shorthand <bool>` | `svelteAllowShorthand: <bool>` |

### Svelte Self Closing Elements

Whether or not empty elements (such as `div`s) should be self-closed or not.

Example:

<!-- prettier-ignore -->
```html
<!-- svelteSelfCloseElements: "always" -->
<div />

<!-- svelteSelfCloseElements: "never" -->
<div></div>
```

| Default | CLI Override | API Override |
| --------- | ------------------------------------ | ---------------------------------- | -------- |
| `"never"` | `--svelte-self-close-elements <str>` | `svelteSelfCloseElements: "always" | "never"` |

### Svelte Self Closing Components

Whether or not empty components should be self-closed or not.

Example:

<!-- prettier-ignore -->
```html
<!-- svelteSelfCloseComponents: "always" -->
<Component />

<!-- svelteSelfCloseComponents: "never" -->
<Component></Component>
```

| Default | CLI Override | API Override |
| ---------- | -------------------------------------- | ------------------------------------ | -------- |
| `"always"` | `--svelte-self-close-components <str>` | `svelteSelfCloseComponents: "always" | "never"` |

### Svelte Bracket New Line

> Deprecated since 2.5.0. Use Prettier 2.4.0 and [bracketSameLine](https://prettier.io/docs/en/options.html#bracket-line) instead.
Expand All @@ -103,6 +147,7 @@ Put the `>` of a multiline element on a new line. Roughly the Svelte equivalent

Example:

<!-- prettier-ignore -->
```html
<!-- before formatting -->
<span><div>foo</div><span>bar</span></span>
Expand Down Expand Up @@ -147,11 +192,11 @@ Whether or not to indent the code inside `<script>` and `<style>` tags in Svelte

```json
{
"svelteSortOrder" : "options-styles-scripts-markup",
"svelteStrictMode": true,
"svelteBracketNewLine": false,
"svelteAllowShorthand": false,
"svelteIndentScriptAndStyle": false
"svelteSortOrder": "options-styles-scripts-markup",
"svelteStrictMode": true,
"svelteBracketNewLine": false,
"svelteAllowShorthand": false,
"svelteIndentScriptAndStyle": false
}
```

Expand All @@ -162,12 +207,12 @@ There is a [Tailwind Prettier Plugin](https://github.com/tailwindlabs/prettier-p
```json5
// .prettierrc
{
// ..
"plugins": [
"prettier-plugin-svelte",
"prettier-plugin-tailwindcss" // MUST come last
],
"pluginSearchDirs": false
// ..
plugins: [
'prettier-plugin-svelte',
'prettier-plugin-tailwindcss', // MUST come last
],
pluginSearchDirs: false,
}
```

Expand All @@ -178,8 +223,8 @@ Since we are using configuration overrides to handle svelte files, you might als
```json5
// settings.json
{
// ..
"prettier.documentSelectors": ["**/*.svelte"],
// ..
'prettier.documentSelectors': ['**/*.svelte'],
}
```

Expand All @@ -189,12 +234,14 @@ Since we are using configuration overrides to handle svelte files, you might als

If you are wondering why this code

<!-- prettier-ignore -->
```html
<span><span>assume very long text</span></span>
```

becomes this

<!-- prettier-ignore -->
```html
<span
><span>assume very long text</span
Expand Down
9 changes: 5 additions & 4 deletions src/options.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ParserOptions as PrettierParserOptions, SupportOption } from 'prettier';

export interface ParserOptions<T = any> extends PrettierParserOptions<T>, Partial<PluginOptions> {
}
export interface ParserOptions<T = any> extends PrettierParserOptions<T>, Partial<PluginOptions> {}

export interface PluginOptions {
svelteSortOrder: SortOrder;
Expand Down Expand Up @@ -60,7 +59,7 @@ export const options: Record<keyof PluginOptions, SupportOption> = {
category: 'Svelte',
type: 'boolean',
default: false,
description: 'More strict HTML syntax: self-closed tags, quotes in attributes',
description: 'More strict HTML syntax: Quotes in attributes, no self-closing DOM tags',
},
svelteBracketNewLine: {
category: 'Svelte',
Expand Down Expand Up @@ -124,7 +123,9 @@ export type SortOrderPart = 'scripts' | 'markup' | 'styles' | 'options';

const sortOrderSeparator = '-';

export function parseSortOrder(sortOrder: SortOrder = 'options-scripts-markup-styles'): SortOrderPart[] {
export function parseSortOrder(
sortOrder: SortOrder = 'options-scripts-markup-styles',
): SortOrderPart[] {
if (sortOrder === 'none') {
return [];
}
Expand Down
31 changes: 18 additions & 13 deletions src/print/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,18 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
);
const isEmpty = node.children.every((child) => isEmptyTextNode(child));
const isDoctypeTag = node.name.toUpperCase() === '!DOCTYPE';
const didSelfClose = options.originalText[node.end - 2] === '/';

const isSelfClosingTag =
isEmpty &&
(!options.svelteStrictMode ||
node.type !== 'Element' ||
((((node.type === 'Element' && !options.svelteStrictMode) ||
node.type === 'Head' ||
node.type === 'InlineComponent' ||
node.type === 'SlotTemplate' ||
node.type === 'Title') &&
didSelfClose) ||
node.type === 'Slot' ||
node.type === 'Window' ||
selfClosingTags.indexOf(node.name) !== -1 ||
isDoctypeTag);

Expand Down Expand Up @@ -290,7 +297,7 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
group([
possibleThisBinding,
...attributes,
hugStart
hugStart && !isEmpty
? ''
: !bracketSameLine && !isPreTagContent(path)
? dedent(softline)
Expand Down Expand Up @@ -430,10 +437,10 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
}
case 'Attribute': {
if (isOrCanBeConvertedToShorthand(node)) {
if (options.svelteStrictMode) {
return [node.name, '="{', node.name, '}"'];
} else if (options.svelteAllowShorthand) {
if (options.svelteAllowShorthand) {
return ['{', node.name, '}'];
} else if (options.svelteStrictMode) {
return [node.name, '="{', node.name, '}"'];
} else {
return [node.name, '={', node.name, '}'];
}
Expand Down Expand Up @@ -613,8 +620,7 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
node.name,
node.expression.type === 'Identifier' &&
node.expression.name === node.name &&
options.svelteAllowShorthand &&
!options.svelteStrictMode
options.svelteAllowShorthand
? ''
: ['=', ...printJsExpression()],
];
Expand All @@ -624,8 +630,7 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
node.name,
node.expression.type === 'Identifier' &&
node.expression.name === node.name &&
options.svelteAllowShorthand &&
!options.svelteStrictMode
options.svelteAllowShorthand
? ''
: ['=', ...printJsExpression()],
];
Expand All @@ -637,10 +642,10 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
];

if (isOrCanBeConvertedToShorthand(node) || node.value === true) {
if (options.svelteStrictMode) {
return [...prefix, '="{', node.name, '}"'];
} else if (options.svelteAllowShorthand) {
if (options.svelteAllowShorthand) {
return [...prefix];
} else if (options.svelteStrictMode) {
return [...prefix, '="{', node.name, '}"'];
} else {
return [...prefix, '={', node.name, '}'];
}
Expand Down
2 changes: 1 addition & 1 deletion test/formatting/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import test from 'ava';
import { readdirSync, readFileSync, existsSync } from 'fs';
import { format } from 'prettier';
import * as SveltePlugin from '../../src'
import * as SveltePlugin from '../../src';

let dirs = readdirSync('test/formatting/samples');
const endsWithOnly = (f: string): boolean => f.endsWith('.only');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
data-value={array.map((item) => {
return item + 1
})}
/>
></div>
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
data-value={array.map((item) => {
return item + 1;
})}
/>
></div>
2 changes: 1 addition & 1 deletion test/formatting/samples/attribute-wrap-several/input.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<div id="x" class="y" title="A really long title" hidden on:click={do_something} draggable="false" data-my-prop />
<div id="x" class="y" title="A really long title" hidden on:click={do_something} draggable="false" data-my-prop></div>
2 changes: 1 addition & 1 deletion test/formatting/samples/attribute-wrap-several/output.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
on:click={do_something}
draggable="false"
data-my-prop
/>
></div>
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<div foo={foo} />
<div foo={foo}></div>
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<div {foo} />
<div {foo}></div>
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<div />
<div></div>
2 changes: 1 addition & 1 deletion test/formatting/samples/empty-element/output.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<div />
<div></div>
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

<span id="x" class="y">Copy</span>

<div id="x" class:y={true} style:marginLeft="4px" on:click={onClick} />
<div id="x" class:y={true} style:marginLeft="4px" on:click={onClick}></div>

<svelte:body on:mouseenter={handleMouseenter} on:mouseleave={handleMouseleave} />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
class:y={true}
style:marginLeft="4px"
on:click={onClick}
/>
></div>

<svelte:body
on:mouseenter={handleMouseenter}
Expand Down
14 changes: 14 additions & 0 deletions test/formatting/samples/strict-mode-false/input.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,17 @@
<input style:value />
<input style:value={value} />
<input style:value="{value}" />

<input value="{foo}" />
<input value={foo} />
<input bind:value="{foo}" />
<input bind:value={foo} />
<input class:value="{foo}" />
<input class:value={foo} />
<input style:value="{foo}" />
<input style:value={foo} />

<div />
<div></div>
<Component />
<Component></Component>
14 changes: 14 additions & 0 deletions test/formatting/samples/strict-mode-false/output.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,17 @@
<input style:value />
<input style:value />
<input style:value />

<input value={foo} />
<input value={foo} />
<input bind:value={foo} />
<input bind:value={foo} />
<input class:value={foo} />
<input class:value={foo} />
<input style:value={foo} />
<input style:value={foo} />

<div />
<div></div>
<Component />
<Component></Component>
14 changes: 14 additions & 0 deletions test/formatting/samples/strict-mode-true/input.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,17 @@
<input style:value />
<input style:value={value} />
<input style:value="{value}" />

<input value="{foo}" />
<input value={foo} />
<input bind:value="{foo}" />
<input bind:value={foo} />
<input class:value="{foo}" />
<input class:value={foo} />
<input style:value="{foo}" />
<input style:value={foo} />

<div />
<div></div>
<Component />
<Component></Component>
Loading