Skip to content

Commit 23f3dc4

Browse files
authored
breaking: new options, deprecate svelteStrictMode (#380)
- 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>`. `svelteStrictMode` only has effect on elements (not allowing self-closing non-void-ones) - `svelteAllowShorthand` now takes precedence over `svelteStrictMode`, which no longer has any effect on that behavior closes #284 closes #279 closes #238 related to #348 related to #377 superseeds / closes #379 as less options = better
1 parent 19654d5 commit 23f3dc4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+239
-123
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
- (breaking) requires `prettier` version 3
66
- (breaking) requires node version 14 or higher
7+
- (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)
8+
- (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
79

810
## 2.10.1
911

README.md

+62-15
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ Install `prettier` and `prettier-plugin-svelte` as dev dependencies in your proj
3030
Then format your code using Prettier CLI. You may need to add `--plugin-search-dir=.`
3131

3232
As a one-time run:
33+
3334
```
3435
npx prettier --write --plugin-search-dir=. ./**/*.html
3536
```
3637

3738
As part of your scripts in `package.json`:
39+
3840
```
3941
"format": "prettier --write --plugin-search-dir=. ./**/*.html"
4042
```
@@ -43,7 +45,7 @@ If you want to customize some formatting behavior, see section "Options" below.
4345

4446
## Options
4547

46-
``Configurations are optional``
48+
`Configurations are optional`
4749

4850
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.
4951

@@ -61,10 +63,13 @@ Format: join the keywords `options`, `scripts`, `markup`, `styles` with a `-` in
6163
6264
### Svelte Strict Mode
6365

64-
More strict HTML syntax: less self-closed tags, quotes in attributes, no attribute shorthand (overrules `svelteAllowShorthand`).
66+
More strict HTML syntax: Quotes in attributes and no self-closing DOM elements (except void elements).
67+
68+
> In version 2 this overruled `svelteAllowShorthand`, which is no longer the case.
6569
6670
Example:
6771

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

8489
Example:
8590

91+
<!-- prettier-ignore -->
8692
```html
8793
<!-- allowShorthand: true -->
8894
<input type="text" {value} />
@@ -95,6 +101,44 @@ Example:
95101
| ------- | --------------------------------- | ------------------------------ |
96102
| `true` | `--svelte-allow-shorthand <bool>` | `svelteAllowShorthand: <bool>` |
97103

104+
### Svelte Self Closing Elements
105+
106+
Whether or not empty elements (such as `div`s) should be self-closed or not.
107+
108+
Example:
109+
110+
<!-- prettier-ignore -->
111+
```html
112+
<!-- svelteSelfCloseElements: "always" -->
113+
<div />
114+
115+
<!-- svelteSelfCloseElements: "never" -->
116+
<div></div>
117+
```
118+
119+
| Default | CLI Override | API Override |
120+
| --------- | ------------------------------------ | ---------------------------------- | -------- |
121+
| `"never"` | `--svelte-self-close-elements <str>` | `svelteSelfCloseElements: "always" | "never"` |
122+
123+
### Svelte Self Closing Components
124+
125+
Whether or not empty components should be self-closed or not.
126+
127+
Example:
128+
129+
<!-- prettier-ignore -->
130+
```html
131+
<!-- svelteSelfCloseComponents: "always" -->
132+
<Component />
133+
134+
<!-- svelteSelfCloseComponents: "never" -->
135+
<Component></Component>
136+
```
137+
138+
| Default | CLI Override | API Override |
139+
| ---------- | -------------------------------------- | ------------------------------------ | -------- |
140+
| `"always"` | `--svelte-self-close-components <str>` | `svelteSelfCloseComponents: "always" | "never"` |
141+
98142
### Svelte Bracket New Line
99143

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

104148
Example:
105149

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

148193
```json
149194
{
150-
"svelteSortOrder" : "options-styles-scripts-markup",
151-
"svelteStrictMode": true,
152-
"svelteBracketNewLine": false,
153-
"svelteAllowShorthand": false,
154-
"svelteIndentScriptAndStyle": false
195+
"svelteSortOrder": "options-styles-scripts-markup",
196+
"svelteStrictMode": true,
197+
"svelteBracketNewLine": false,
198+
"svelteAllowShorthand": false,
199+
"svelteIndentScriptAndStyle": false
155200
}
156201
```
157202

@@ -162,12 +207,12 @@ There is a [Tailwind Prettier Plugin](https://github.com/tailwindlabs/prettier-p
162207
```json5
163208
// .prettierrc
164209
{
165-
// ..
166-
"plugins": [
167-
"prettier-plugin-svelte",
168-
"prettier-plugin-tailwindcss" // MUST come last
169-
],
170-
"pluginSearchDirs": false
210+
// ..
211+
plugins: [
212+
'prettier-plugin-svelte',
213+
'prettier-plugin-tailwindcss', // MUST come last
214+
],
215+
pluginSearchDirs: false,
171216
}
172217
```
173218

@@ -178,8 +223,8 @@ Since we are using configuration overrides to handle svelte files, you might als
178223
```json5
179224
// settings.json
180225
{
181-
// ..
182-
"prettier.documentSelectors": ["**/*.svelte"],
226+
// ..
227+
'prettier.documentSelectors': ['**/*.svelte'],
183228
}
184229
```
185230

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

190235
If you are wondering why this code
191236

237+
<!-- prettier-ignore -->
192238
```html
193239
<span><span>assume very long text</span></span>
194240
```
195241

196242
becomes this
197243

244+
<!-- prettier-ignore -->
198245
```html
199246
<span
200247
><span>assume very long text</span

src/options.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { ParserOptions as PrettierParserOptions, SupportOption } from 'prettier';
22

3-
export interface ParserOptions<T = any> extends PrettierParserOptions<T>, Partial<PluginOptions> {
4-
}
3+
export interface ParserOptions<T = any> extends PrettierParserOptions<T>, Partial<PluginOptions> {}
54

65
export interface PluginOptions {
76
svelteSortOrder: SortOrder;
@@ -60,7 +59,7 @@ export const options: Record<keyof PluginOptions, SupportOption> = {
6059
category: 'Svelte',
6160
type: 'boolean',
6261
default: false,
63-
description: 'More strict HTML syntax: self-closed tags, quotes in attributes',
62+
description: 'More strict HTML syntax: Quotes in attributes, no self-closing DOM tags',
6463
},
6564
svelteBracketNewLine: {
6665
category: 'Svelte',
@@ -124,7 +123,9 @@ export type SortOrderPart = 'scripts' | 'markup' | 'styles' | 'options';
124123

125124
const sortOrderSeparator = '-';
126125

127-
export function parseSortOrder(sortOrder: SortOrder = 'options-scripts-markup-styles'): SortOrderPart[] {
126+
export function parseSortOrder(
127+
sortOrder: SortOrder = 'options-scripts-markup-styles',
128+
): SortOrderPart[] {
128129
if (sortOrder === 'none') {
129130
return [];
130131
}

src/print/index.ts

+18-13
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,18 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
209209
);
210210
const isEmpty = node.children.every((child) => isEmptyTextNode(child));
211211
const isDoctypeTag = node.name.toUpperCase() === '!DOCTYPE';
212+
const didSelfClose = options.originalText[node.end - 2] === '/';
212213

213214
const isSelfClosingTag =
214215
isEmpty &&
215-
(!options.svelteStrictMode ||
216-
node.type !== 'Element' ||
216+
((((node.type === 'Element' && !options.svelteStrictMode) ||
217+
node.type === 'Head' ||
218+
node.type === 'InlineComponent' ||
219+
node.type === 'SlotTemplate' ||
220+
node.type === 'Title') &&
221+
didSelfClose) ||
222+
node.type === 'Slot' ||
223+
node.type === 'Window' ||
217224
selfClosingTags.indexOf(node.name) !== -1 ||
218225
isDoctypeTag);
219226

@@ -290,7 +297,7 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
290297
group([
291298
possibleThisBinding,
292299
...attributes,
293-
hugStart
300+
hugStart && !isEmpty
294301
? ''
295302
: !bracketSameLine && !isPreTagContent(path)
296303
? dedent(softline)
@@ -430,10 +437,10 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
430437
}
431438
case 'Attribute': {
432439
if (isOrCanBeConvertedToShorthand(node)) {
433-
if (options.svelteStrictMode) {
434-
return [node.name, '="{', node.name, '}"'];
435-
} else if (options.svelteAllowShorthand) {
440+
if (options.svelteAllowShorthand) {
436441
return ['{', node.name, '}'];
442+
} else if (options.svelteStrictMode) {
443+
return [node.name, '="{', node.name, '}"'];
437444
} else {
438445
return [node.name, '={', node.name, '}'];
439446
}
@@ -613,8 +620,7 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
613620
node.name,
614621
node.expression.type === 'Identifier' &&
615622
node.expression.name === node.name &&
616-
options.svelteAllowShorthand &&
617-
!options.svelteStrictMode
623+
options.svelteAllowShorthand
618624
? ''
619625
: ['=', ...printJsExpression()],
620626
];
@@ -624,8 +630,7 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
624630
node.name,
625631
node.expression.type === 'Identifier' &&
626632
node.expression.name === node.name &&
627-
options.svelteAllowShorthand &&
628-
!options.svelteStrictMode
633+
options.svelteAllowShorthand
629634
? ''
630635
: ['=', ...printJsExpression()],
631636
];
@@ -637,10 +642,10 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
637642
];
638643

639644
if (isOrCanBeConvertedToShorthand(node) || node.value === true) {
640-
if (options.svelteStrictMode) {
641-
return [...prefix, '="{', node.name, '}"'];
642-
} else if (options.svelteAllowShorthand) {
645+
if (options.svelteAllowShorthand) {
643646
return [...prefix];
647+
} else if (options.svelteStrictMode) {
648+
return [...prefix, '="{', node.name, '}"'];
644649
} else {
645650
return [...prefix, '={', node.name, '}'];
646651
}

test/formatting/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import test from 'ava';
22
import { readdirSync, readFileSync, existsSync } from 'fs';
33
import { format } from 'prettier';
4-
import * as SveltePlugin from '../../src'
4+
import * as SveltePlugin from '../../src';
55

66
let dirs = readdirSync('test/formatting/samples');
77
const endsWithOnly = (f: string): boolean => f.endsWith('.only');

test/formatting/samples/attribute-with-linebreaks/input.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
data-value={array.map((item) => {
66
return item + 1
77
})}
8-
/>
8+
></div>

test/formatting/samples/attribute-with-linebreaks/output.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
data-value={array.map((item) => {
66
return item + 1;
77
})}
8-
/>
8+
></div>
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<div id="x" class="y" title="A really long title" hidden on:click={do_something} draggable="false" data-my-prop />
1+
<div id="x" class="y" title="A really long title" hidden on:click={do_something} draggable="false" data-my-prop></div>

test/formatting/samples/attribute-wrap-several/output.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
on:click={do_something}
77
draggable="false"
88
data-my-prop
9-
/>
9+
></div>
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<div foo={foo} />
1+
<div foo={foo}></div>
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<div {foo} />
1+
<div {foo}></div>
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<div />
1+
<div></div>
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<div />
1+
<div></div>

test/formatting/samples/single-attribute-per-line/input.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

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

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

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

test/formatting/samples/single-attribute-per-line/output.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
class:y={true}
3737
style:marginLeft="4px"
3838
on:click={onClick}
39-
/>
39+
></div>
4040

4141
<svelte:body
4242
on:mouseenter={handleMouseenter}

test/formatting/samples/strict-mode-false/input.html

+14
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,17 @@
1212
<input style:value />
1313
<input style:value={value} />
1414
<input style:value="{value}" />
15+
16+
<input value="{foo}" />
17+
<input value={foo} />
18+
<input bind:value="{foo}" />
19+
<input bind:value={foo} />
20+
<input class:value="{foo}" />
21+
<input class:value={foo} />
22+
<input style:value="{foo}" />
23+
<input style:value={foo} />
24+
25+
<div />
26+
<div></div>
27+
<Component />
28+
<Component></Component>

test/formatting/samples/strict-mode-false/output.html

+14
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,17 @@
1212
<input style:value />
1313
<input style:value />
1414
<input style:value />
15+
16+
<input value={foo} />
17+
<input value={foo} />
18+
<input bind:value={foo} />
19+
<input bind:value={foo} />
20+
<input class:value={foo} />
21+
<input class:value={foo} />
22+
<input style:value={foo} />
23+
<input style:value={foo} />
24+
25+
<div />
26+
<div></div>
27+
<Component />
28+
<Component></Component>

test/formatting/samples/strict-mode-true/input.html

+14
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,17 @@
1212
<input style:value />
1313
<input style:value={value} />
1414
<input style:value="{value}" />
15+
16+
<input value="{foo}" />
17+
<input value={foo} />
18+
<input bind:value="{foo}" />
19+
<input bind:value={foo} />
20+
<input class:value="{foo}" />
21+
<input class:value={foo} />
22+
<input style:value="{foo}" />
23+
<input style:value={foo} />
24+
25+
<div />
26+
<div></div>
27+
<Component />
28+
<Component></Component>

0 commit comments

Comments
 (0)