Repository: sveltejs/prettier-plugin-svelte
Pull request #287 (2022-04-08 20:07:31)

Bump trim-off-newlines from 1.0.1 to 1.0.3
Bumps [trim-off-newlines](https://github.com/stevemao/trim-off-newlines) from 1.0.1 to 1.0.3.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/stevemao/trim-off-newlines/commit/c3b28d395cf249f77803e9e42e302d129e8b8a8f"><code>c3b28d3</code></a> 1.0.3</li>
<li><a href="https://github.com/stevemao/trim-off-newlines/commit/6226c958cbbac284a840010eb1f6617fb99a5645"><code>6226c95</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/stevemao/trim-off-newlines/issues/4">#4</a> from Trott/fix-it-again</li>
<li><a href="https://github.com/stevemao/trim-off-newlines/commit/c77691de9130d5c0021301593a1c7e3b3b0ff5a7"><code>c77691d</code></a> fix: remediate ReDOS further</li>
<li><a href="https://github.com/stevemao/trim-off-newlines/commit/76ca93c151b89d34b31feb1482434125b2ac45c3"><code>76ca93c</code></a> chore: pin mocha to version that works with 0.10.x</li>
<li><a href="https://github.com/stevemao/trim-off-newlines/commit/8cd3f73a138dd479db9cfb1b42d235c71499c297"><code>8cd3f73</code></a> 1.0.2</li>
<li><a href="https://github.com/stevemao/trim-off-newlines/commit/fcbb73d7065d6332c302e828c6bd215a6cc69748"><code>fcbb73d</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/stevemao/trim-off-newlines/issues/3">#3</a> from Trott/patch-1</li>
<li><a href="https://github.com/stevemao/trim-off-newlines/commit/6d894768a492c1f7d1e5e80645c43ed9416432af"><code>6d89476</code></a> fix: update regular expression to remove ReDOS</li>
<li><a href="https://github.com/stevemao/trim-off-newlines/commit/0cd87f5414400ab505f867e5a465596ebe61de98"><code>0cd87f5</code></a> chore: pin xo to latest version that works with current code</li>
<li>See full diff in <a href="https://github.com/stevemao/trim-off-newlines/compare/v1.0.1...v1.0.3">compare view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a href="https://www.npmjs.com/~trott">trott</a>, a new releaser for trim-off-newlines since your current version.</p>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=trim-off-newlines&package-manager=npm_and_yarn&previous-version=1.0.1&new-version=1.0.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
- `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language
- `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language
- `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language
- `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language

You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/sveltejs/prettier-plugin-svelte/network/alerts).

</details>


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8dbe8c8..0830db0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,90 +1,110 @@
 # prettier-plugin-svelte changelog
 
-## 2.7.0 (Unreleased)
+## 2.9.0
 
-* (feat) support `<svelte:element>` ([#285](https://github.com/sveltejs/prettier-plugin-svelte/pull/285)) 
-* (fix) respect whitespace "ignore" setting for components ([#281](https://github.com/sveltejs/prettier-plugin-svelte/issues/281)) 
+-   (feat) support style modifiers ([#330](https://github.com/sveltejs/prettier-plugin-svelte/issues/330))
+-   (fix) respect strict mode and shorthand options when formatting style/class directives ([#328](https://github.com/sveltejs/prettier-plugin-svelte/issues/328))
+
+## 2.8.1
+
+-   (fix) format `{#await .. catch ..}..{/await}` correctly ([#323](https://github.com/sveltejs/prettier-plugin-svelte/issues/323))
+-   (fix) respect strict mode and shorthand options when formatting bindings ([#321](https://github.com/sveltejs/prettier-plugin-svelte/issues/321))
+
+## 2.8.0
+
+-   (feat) support `singleAttributePerLine` Prettier option ([#305](https://github.com/sveltejs/prettier-plugin-svelte/issues/305))
+-   (feat) add `svelteSortOrder: none` Prettier option which skips reordering scripts/styles/html ([#305](https://github.com/sveltejs/prettier-plugin-svelte/issues/314))
+
+## 2.7.1
+
+-   (fix) check for snipped content in JS expressions ([#290](https://github.com/sveltejs/prettier-plugin-svelte/issues/290))
+-   (fix) handle `<!DOCTYPE>` ([#298](https://github.com/sveltejs/prettier-plugin-svelte/issues/298))
+
+## 2.7.0
+
+-   (feat) Support `<svelte:element>` ([#285](https://github.com/sveltejs/prettier-plugin-svelte/pull/285))
+-   (fix) Respect `htmlWhitespaceSensitivity: 'ignore'` setting in components ([#281](https://github.com/sveltejs/prettier-plugin-svelte/issues/281))
 
 ## 2.6.0
 
-* (feat) Support `{@const}` tag ([#272](https://github.com/sveltejs/prettier-plugin-svelte/issues/272))
-* (feat) Support `style:` directive (requires Svelte 3.46.1 or later) ([#274](https://github.com/sveltejs/prettier-plugin-svelte/issues/274))
+-   (feat) Support `{@const}` tag ([#272](https://github.com/sveltejs/prettier-plugin-svelte/issues/272))
+-   (feat) Support `style:` directive (requires Svelte 3.46.1 or later) ([#274](https://github.com/sveltejs/prettier-plugin-svelte/issues/274))
 
 ## 2.5.1
 
-* (fix) Better handling of destructured values with defaults in `{#each}` and `{#await}` blocks ([#269](https://github.com/sveltejs/prettier-plugin-svelte/issues/269))
-* (fix) Prevent `<script>`/`<style>` contents from being erased in certain cases ([#268](https://github.com/sveltejs/prettier-plugin-svelte/issues/268))
-* (fix) Format `{expressions}` inside `<pre>` tags ([#266](https://github.com/sveltejs/prettier-plugin-svelte/issues/266))
+-   (fix) Better handling of destructured values with defaults in `{#each}` and `{#await}` blocks ([#269](https://github.com/sveltejs/prettier-plugin-svelte/issues/269))
+-   (fix) Prevent `<script>`/`<style>` contents from being erased in certain cases ([#268](https://github.com/sveltejs/prettier-plugin-svelte/issues/268))
+-   (fix) Format `{expressions}` inside `<pre>` tags ([#266](https://github.com/sveltejs/prettier-plugin-svelte/issues/266))
 
 ## 2.5.0
 
-* (feat) Support `bracketSameLine` option and deprecate `svelteBracketNewLine` ([#251](https://github.com/sveltejs/prettier-plugin-svelte/pull/251))
-* (fix) Prevent script/style contents from being erased in certain cases ([#255](https://github.com/sveltejs/prettier-plugin-svelte/issues/255))
-* (fix) Properly format nested array patterns ([#259](https://github.com/sveltejs/prettier-plugin-svelte/issues/259))
+-   (feat) Support `bracketSameLine` option and deprecate `svelteBracketNewLine` ([#251](https://github.com/sveltejs/prettier-plugin-svelte/pull/251))
+-   (fix) Prevent script/style contents from being erased in certain cases ([#255](https://github.com/sveltejs/prettier-plugin-svelte/issues/255))
+-   (fix) Properly format nested array patterns ([#259](https://github.com/sveltejs/prettier-plugin-svelte/issues/259))
 
 ## 2.4.0
 
-* (feat) Add support for formatting Pug inside `<template>` tags, if the corresponding plugin is available ([#248](https://github.com/sveltejs/prettier-plugin-svelte/pull/248))
-* (fix) Adjust checks for whether we're inside another tag when snipping tags ([#244](https://github.com/sveltejs/prettier-plugin-svelte/issues/244), [#246](https://github.com/sveltejs/prettier-plugin-svelte/issues/246))
+-   (feat) Add support for formatting Pug inside `<template>` tags, if the corresponding plugin is available ([#248](https://github.com/sveltejs/prettier-plugin-svelte/pull/248))
+-   (fix) Adjust checks for whether we're inside another tag when snipping tags ([#244](https://github.com/sveltejs/prettier-plugin-svelte/issues/244), [#246](https://github.com/sveltejs/prettier-plugin-svelte/issues/246))
 
 ## 2.3.1
 
-* (fix) More robust check for `hardline` to prevent trailing empty lines in `<style>`/`<script>` tags ([#222](https://github.com/sveltejs/prettier-plugin-svelte/issues/222))
+-   (fix) More robust check for `hardline` to prevent trailing empty lines in `<style>`/`<script>` tags ([#222](https://github.com/sveltejs/prettier-plugin-svelte/issues/222))
 
 ## 2.3.0
 
-* (fix) Adjust snip regex to not break commented-out `<script>`/`<style>` tags ([#212](https://github.com/sveltejs/prettier-plugin-svelte/issues/212))
-* (fix) Don't snip `<style>` tags that are inside `<script>` tags ([#219](https://github.com/sveltejs/prettier-plugin-svelte/issues/219), [#70](https://github.com/sveltejs/prettier-plugin-svelte/issues/70))
-* (fix) Better formatting of long attribute values with mustache tags in between ([#221](https://github.com/sveltejs/prettier-plugin-svelte/pull/221))
-* (fix) Format properly when using Prettier 2.3.0+ ([#222](https://github.com/sveltejs/prettier-plugin-svelte/issues/222))
-* (fix) Keep parentheses in `<script>` tags for which JS is assumed ([#218](https://github.com/sveltejs/prettier-plugin-svelte/issues/218))
-* (feat) Support range ignores at HTML top level ([#225](https://github.com/sveltejs/prettier-plugin-svelte/issues/225))
+-   (fix) Adjust snip regex to not break commented-out `<script>`/`<style>` tags ([#212](https://github.com/sveltejs/prettier-plugin-svelte/issues/212))
+-   (fix) Don't snip `<style>` tags that are inside `<script>` tags ([#219](https://github.com/sveltejs/prettier-plugin-svelte/issues/219), [#70](https://github.com/sveltejs/prettier-plugin-svelte/issues/70))
+-   (fix) Better formatting of long attribute values with mustache tags in between ([#221](https://github.com/sveltejs/prettier-plugin-svelte/pull/221))
+-   (fix) Format properly when using Prettier 2.3.0+ ([#222](https://github.com/sveltejs/prettier-plugin-svelte/issues/222))
+-   (fix) Keep parentheses in `<script>` tags for which JS is assumed ([#218](https://github.com/sveltejs/prettier-plugin-svelte/issues/218))
+-   (feat) Support range ignores at HTML top level ([#225](https://github.com/sveltejs/prettier-plugin-svelte/issues/225))
 
 ## 2.2.0
 
-* Add support for `<svelte:fragment>` ([#213](https://github.com/sveltejs/prettier-plugin-svelte/pull/213))
+-   Add support for `<svelte:fragment>` ([#213](https://github.com/sveltejs/prettier-plugin-svelte/pull/213))
 
 ## 2.1.6
 
-* Fix incorrect removal of comment ([#207](https://github.com/sveltejs/prettier-plugin-svelte/issues/207))
+-   Fix incorrect removal of comment ([#207](https://github.com/sveltejs/prettier-plugin-svelte/issues/207))
 
 ## 2.1.5
 
-* Fix retrieval of comment belonging to `<script>`/`<style>` block ([#205](https://github.com/sveltejs/prettier-plugin-svelte/issues/205))
+-   Fix retrieval of comment belonging to `<script>`/`<style>` block ([#205](https://github.com/sveltejs/prettier-plugin-svelte/issues/205))
 
 ## 2.1.4
 
-* Don't print an empty line at the end of code embedded inside Markdown (further fixes) ([#202](https://github.com/sveltejs/prettier-plugin-svelte/issues/202))
+-   Don't print an empty line at the end of code embedded inside Markdown (further fixes) ([#202](https://github.com/sveltejs/prettier-plugin-svelte/issues/202))
 
 ## 2.1.3
 
-* Don't print an empty line at the end of code embedded inside Markdown ([#202](https://github.com/sveltejs/prettier-plugin-svelte/issues/202))
+-   Don't print an empty line at the end of code embedded inside Markdown ([#202](https://github.com/sveltejs/prettier-plugin-svelte/issues/202))
 
 ## 2.1.2
 
-* Keep whitespace around `<script>`/`<style>` tags ([#197](https://github.com/sveltejs/prettier-plugin-svelte/issues/197))
-* Make `<script>`/`<style>` tag snipping case-sensitive ([#198](https://github.com/sveltejs/prettier-plugin-svelte/issues/198))
+-   Keep whitespace around `<script>`/`<style>` tags ([#197](https://github.com/sveltejs/prettier-plugin-svelte/issues/197))
+-   Make `<script>`/`<style>` tag snipping case-sensitive ([#198](https://github.com/sveltejs/prettier-plugin-svelte/issues/198))
 
 ## 2.1.1
 
-* Fix `svelteBracketNewLine: true` sometimes not having `>` on a separate line ([#194](https://github.com/sveltejs/prettier-plugin-svelte/issues/194))
+-   Fix `svelteBracketNewLine: true` sometimes not having `>` on a separate line ([#194](https://github.com/sveltejs/prettier-plugin-svelte/issues/194))
 
 ## 2.1.0
 
-* Support Prettier's `htmlWhitespaceSensitivity` setting
-* When `svelteBracketNewLine` is set to `true` and only the closing tag has whitespace before it, print the closing `>` on a separate line
+-   Support Prettier's `htmlWhitespaceSensitivity` setting
+-   When `svelteBracketNewLine` is set to `true` and only the closing tag has whitespace before it, print the closing `>` on a separate line
 
 ## 2.0.3
 
-* When `svelteBracketNewLine` is set to `false`, don't print the closing `>` in a separate line if possible ([#183](https://github.com/sveltejs/prettier-plugin-svelte/issues/183))
+-   When `svelteBracketNewLine` is set to `false`, don't print the closing `>` in a separate line if possible ([#183](https://github.com/sveltejs/prettier-plugin-svelte/issues/183))
 
 ## 2.0.2
 
-* Fix formatting of `<template>` tags with an unsupported language inside
+-   Fix formatting of `<template>` tags with an unsupported language inside
 
 ## 2.0.1
 
-* Fix formatting of inline element when there's a line at the start/end ([#183](https://github.com/sveltejs/prettier-plugin-svelte/issues/183))
+-   Fix formatting of inline element when there's a line at the start/end ([#183](https://github.com/sveltejs/prettier-plugin-svelte/issues/183))
 
 ## 2.0.0
 
@@ -92,116 +112,116 @@ This release comes with a rewrite of the HTML formatting. The output is now much
 
 The complete list of changes:
 
-* Rework the tag breaking logic with the goal to be more in line with how Prettier formats standard HTML. This includes respecting the user's decision to have child tags in separate lines even if they don't exceed the maximum line width ([#143](https://github.com/sveltejs/prettier-plugin-svelte/issues/143), [#117](https://github.com/sveltejs/prettier-plugin-svelte/issues/117)). This is a breaking change because tags are broken up differently now than before.
-* `<svelte:options>` is now part of `svelteSortOrder`. Default sort order is now `options-scripts-markup-styles`. This is a breaking change. ([#73](https://github.com/sveltejs/prettier-plugin-svelte/issues/73))
-* `svelteBracketNewLine` defaults to `true` now to be more in line with how Prettier formats standard HTML. This is a breaking change
-* Fix formatting of fenced Svelte code blocks inside Markdown ([#129](https://github.com/sveltejs/prettier-plugin-svelte/issues/129))
-* Everything that is not explicitly a block element is now treated as an inline element, including components. This is a breaking change ([#159](https://github.com/sveltejs/prettier-plugin-svelte/issues/159))
-* Single quotes are no longer forced except inside quoted attributes/events/etc. This is a breaking change ([#94](https://github.com/sveltejs/prettier-plugin-svelte/issues/94))
-* If the content inside a `{tag}` is too long, break it up if possible (excluding `{#if}`/`{#await}`/etc. blocks). This is a breaking change ([#170](https://github.com/sveltejs/prettier-plugin-svelte/issues/170))
-* If the content of a `<script>`/`<style>` tag is completely empty (no whitespace), don't put the closing tag on a new line ([#87](https://github.com/sveltejs/prettier-plugin-svelte/issues/87))
+-   Rework the tag breaking logic with the goal to be more in line with how Prettier formats standard HTML. This includes respecting the user's decision to have child tags in separate lines even if they don't exceed the maximum line width ([#143](https://github.com/sveltejs/prettier-plugin-svelte/issues/143), [#117](https://github.com/sveltejs/prettier-plugin-svelte/issues/117)). This is a breaking change because tags are broken up differently now than before.
+-   `<svelte:options>` is now part of `svelteSortOrder`. Default sort order is now `options-scripts-markup-styles`. This is a breaking change. ([#73](https://github.com/sveltejs/prettier-plugin-svelte/issues/73))
+-   `svelteBracketNewLine` defaults to `true` now to be more in line with how Prettier formats standard HTML. This is a breaking change
+-   Fix formatting of fenced Svelte code blocks inside Markdown ([#129](https://github.com/sveltejs/prettier-plugin-svelte/issues/129))
+-   Everything that is not explicitly a block element is now treated as an inline element, including components. This is a breaking change ([#159](https://github.com/sveltejs/prettier-plugin-svelte/issues/159))
+-   Single quotes are no longer forced except inside quoted attributes/events/etc. This is a breaking change ([#94](https://github.com/sveltejs/prettier-plugin-svelte/issues/94))
+-   If the content inside a `{tag}` is too long, break it up if possible (excluding `{#if}`/`{#await}`/etc. blocks). This is a breaking change ([#170](https://github.com/sveltejs/prettier-plugin-svelte/issues/170))
+-   If the content of a `<script>`/`<style>` tag is completely empty (no whitespace), don't put the closing tag on a new line ([#87](https://github.com/sveltejs/prettier-plugin-svelte/issues/87))
 
 ## 1.4.2
 
-* Pass options to embedded parser ([#162](https://github.com/sveltejs/prettier-plugin-svelte/issues/162))
-* Fall back to raw text if there is a parser error in a JS expression inside a moustache tag ([#163](https://github.com/sveltejs/prettier-plugin-svelte/issues/163))
+-   Pass options to embedded parser ([#162](https://github.com/sveltejs/prettier-plugin-svelte/issues/162))
+-   Fall back to raw text if there is a parser error in a JS expression inside a moustache tag ([#163](https://github.com/sveltejs/prettier-plugin-svelte/issues/163))
 
 ## 1.4.1
 
-* Format next node correctly when previous node has a comment as last child ([#152](https://github.com/sveltejs/prettier-plugin-svelte/issues/152))
-* Only `prettier-ignore` comments should ignore formatting of next line ([#151](https://github.com/sveltejs/prettier-plugin-svelte/issues/151))
-* Do not encode entities in attribute values ([#29](https://github.com/sveltejs/prettier-plugin-svelte/issues/29))
-* Fix raw printing of unsupported languages ([#156](https://github.com/sveltejs/prettier-plugin-svelte/issues/156))
+-   Format next node correctly when previous node has a comment as last child ([#152](https://github.com/sveltejs/prettier-plugin-svelte/issues/152))
+-   Only `prettier-ignore` comments should ignore formatting of next line ([#151](https://github.com/sveltejs/prettier-plugin-svelte/issues/151))
+-   Do not encode entities in attribute values ([#29](https://github.com/sveltejs/prettier-plugin-svelte/issues/29))
+-   Fix raw printing of unsupported languages ([#156](https://github.com/sveltejs/prettier-plugin-svelte/issues/156))
 
 ## 1.4.0
 
-* Fix print order of attributes and body ([#146](https://github.com/sveltejs/prettier-plugin-svelte/issues/146))
-* Support the new `{#key}` block introduced in Svelte 3.28.0 ([#147](https://github.com/sveltejs/prettier-plugin-svelte/pull/147))
+-   Fix print order of attributes and body ([#146](https://github.com/sveltejs/prettier-plugin-svelte/issues/146))
+-   Support the new `{#key}` block introduced in Svelte 3.28.0 ([#147](https://github.com/sveltejs/prettier-plugin-svelte/pull/147))
 
 ## 1.3.0
 
-* Add `vscodeLanguageIds` for VS Code consumers, including coc-prettier ([#138](https://github.com/sveltejs/prettier-plugin-svelte/issues/138))
-* Keep comments directly before `<style>`, `<script>` or `<template>` tags together with the tag when reformatting ([#137](https://github.com/sveltejs/prettier-plugin-svelte/issues/137))
-* Keep inline elements together even when inside text ([#139](https://github.com/sveltejs/prettier-plugin-svelte/issues/139))
-* Don't format `class` attributes ([#145](https://github.com/sveltejs/prettier-plugin-svelte/pull/145))
+-   Add `vscodeLanguageIds` for VS Code consumers, including coc-prettier ([#138](https://github.com/sveltejs/prettier-plugin-svelte/issues/138))
+-   Keep comments directly before `<style>`, `<script>` or `<template>` tags together with the tag when reformatting ([#137](https://github.com/sveltejs/prettier-plugin-svelte/issues/137))
+-   Keep inline elements together even when inside text ([#139](https://github.com/sveltejs/prettier-plugin-svelte/issues/139))
+-   Don't format `class` attributes ([#145](https://github.com/sveltejs/prettier-plugin-svelte/pull/145))
 
 ## 1.2.1
 
-* Skip formatting `<style>` or `<script>` tags if in an unsupported language or if `prettier-ignore`d ([#55](https://github.com/sveltejs/prettier-plugin-svelte/issues/55), [#59](https://github.com/sveltejs/prettier-plugin-svelte/issues/59), [#95](https://github.com/sveltejs/prettier-plugin-svelte/issues/95))
-* Make error location properties compatible with both Svelte and Prettier ([#71](https://github.com/sveltejs/prettier-plugin-svelte/issues/71))
-* Handle/preserve comments in event handlers ([#96](https://github.com/sveltejs/prettier-plugin-svelte/issues/96))
-* Fix Node 10 compatibility ([#135](https://github.com/sveltejs/prettier-plugin-svelte/issues/135))
+-   Skip formatting `<style>` or `<script>` tags if in an unsupported language or if `prettier-ignore`d ([#55](https://github.com/sveltejs/prettier-plugin-svelte/issues/55), [#59](https://github.com/sveltejs/prettier-plugin-svelte/issues/59), [#95](https://github.com/sveltejs/prettier-plugin-svelte/issues/95))
+-   Make error location properties compatible with both Svelte and Prettier ([#71](https://github.com/sveltejs/prettier-plugin-svelte/issues/71))
+-   Handle/preserve comments in event handlers ([#96](https://github.com/sveltejs/prettier-plugin-svelte/issues/96))
+-   Fix Node 10 compatibility ([#135](https://github.com/sveltejs/prettier-plugin-svelte/issues/135))
 
 ## 1.2.0
 
-* Don't format contents of `<pre>` or its attributes, apart from `class` ([#28](https://github.com/sveltejs/prettier-plugin-svelte/issues/28))
-* Fix whitespace issues ([#58](https://github.com/sveltejs/prettier-plugin-svelte/issues/58), [#103](https://github.com/sveltejs/prettier-plugin-svelte/issues/103), [#24](https://github.com/sveltejs/prettier-plugin-svelte/issues/24))
-* Add option to disable first level of indentation in `<script>` and `<style>` tags ([#105](https://github.com/sveltejs/prettier-plugin-svelte/issues/105))
-* Fix output when rewriting shorthand attributes to not use the shorthand syntax ([#110](https://github.com/sveltejs/prettier-plugin-svelte/issues/110))
-* Add support for object destructuring reassignment ([#113](https://github.com/sveltejs/prettier-plugin-svelte/issues/113))
+-   Don't format contents of `<pre>` or its attributes, apart from `class` ([#28](https://github.com/sveltejs/prettier-plugin-svelte/issues/28))
+-   Fix whitespace issues ([#58](https://github.com/sveltejs/prettier-plugin-svelte/issues/58), [#103](https://github.com/sveltejs/prettier-plugin-svelte/issues/103), [#24](https://github.com/sveltejs/prettier-plugin-svelte/issues/24))
+-   Add option to disable first level of indentation in `<script>` and `<style>` tags ([#105](https://github.com/sveltejs/prettier-plugin-svelte/issues/105))
+-   Fix output when rewriting shorthand attributes to not use the shorthand syntax ([#110](https://github.com/sveltejs/prettier-plugin-svelte/issues/110))
+-   Add support for object destructuring reassignment ([#113](https://github.com/sveltejs/prettier-plugin-svelte/issues/113))
 
 ## 1.1.1
 
-* Fix bug that breaks plugin when using Prettier v2.1.x ([#123](https://github.com/sveltejs/prettier-plugin-svelte/issues/123))
-* Fix incorrectly escaped regexp which broke style tags followed by "s" ([#118](https://github.com/sveltejs/prettier-plugin-svelte/issues/118))
-* Write to console.error to prevent crash and erasion of files ([#115](https://github.com/sveltejs/prettier-plugin-svelte/issues/115))
+-   Fix bug that breaks plugin when using Prettier v2.1.x ([#123](https://github.com/sveltejs/prettier-plugin-svelte/issues/123))
+-   Fix incorrectly escaped regexp which broke style tags followed by "s" ([#118](https://github.com/sveltejs/prettier-plugin-svelte/issues/118))
+-   Write to console.error to prevent crash and erasion of files ([#115](https://github.com/sveltejs/prettier-plugin-svelte/issues/115))
 
 ## 1.1.0
 
-* Support `<!-- prettier-ignore -->` comments ([#59](https://github.com/sveltejs/prettier-plugin-svelte/issues/59))
-* Fix `{#await}` printing with `{:catch}` but no pending block ([#76](https://github.com/sveltejs/prettier-plugin-svelte/pull/76))
-* Fix `{#await}` printing with only a pending block ([#77](https://github.com/sveltejs/prettier-plugin-svelte/pull/77))
-* Support `{#await}` destructuring ([#83](https://github.com/sveltejs/prettier-plugin-svelte/pull/83))
-* Fix other `{#await}` handling in Svelte versions since 3.20 ([#83](https://github.com/sveltejs/prettier-plugin-svelte/pull/83))
+-   Support `<!-- prettier-ignore -->` comments ([#59](https://github.com/sveltejs/prettier-plugin-svelte/issues/59))
+-   Fix `{#await}` printing with `{:catch}` but no pending block ([#76](https://github.com/sveltejs/prettier-plugin-svelte/pull/76))
+-   Fix `{#await}` printing with only a pending block ([#77](https://github.com/sveltejs/prettier-plugin-svelte/pull/77))
+-   Support `{#await}` destructuring ([#83](https://github.com/sveltejs/prettier-plugin-svelte/pull/83))
+-   Fix other `{#await}` handling in Svelte versions since 3.20 ([#83](https://github.com/sveltejs/prettier-plugin-svelte/pull/83))
 
 ## 1.0.0
 
-* Support Prettier 2
-* Add `svelteAllowShorthand` option
-* This plugin has now become an official Svelte project
+-   Support Prettier 2
+-   Add `svelteAllowShorthand` option
+-   This plugin has now become an official Svelte project
 
 ## 0.7.0
 
-* Add `svelteStrictMode` option
-* Support `{#await}` block shorthand syntax
+-   Add `svelteStrictMode` option
+-   Support `{#await}` block shorthand syntax
 
 ## 0.6.0
 
-* Support nested `<script>` and `<style>` tags
-* Add `svelteSortOrder` option
-* Fix printing of HTML entities
-* Add option to add newline to closing angle bracket
-* Support all `<svelte:*>` elements
-* Throw Svelte parsing errors in format Prettier expects
-* Add handling for `|local` transition modifier
-* Prevent `{#if}` blocks nested in an `{#each}`/`{:else}` from being converted into an `{:else if}`
-* Fix whitespace trimming for lonely wrapped mustache tags
+-   Support nested `<script>` and `<style>` tags
+-   Add `svelteSortOrder` option
+-   Fix printing of HTML entities
+-   Add option to add newline to closing angle bracket
+-   Support all `<svelte:*>` elements
+-   Throw Svelte parsing errors in format Prettier expects
+-   Add handling for `|local` transition modifier
+-   Prevent `{#if}` blocks nested in an `{#each}`/`{:else}` from being converted into an `{:else if}`
+-   Fix whitespace trimming for lonely wrapped mustache tags
 
 ## 0.5.1
 
-* Fix attribute wrapping
+-   Fix attribute wrapping
 
 ## 0.5.0
 
-* Remove .html from list of extensions
-* Use `typescript` as parser to handle both JS and TS
-* Add support for event modifiers
-* Support Unicode content in `<script>` and `<style>` blocks
-* Don't print children for empty elements
-* Improve handling of text nodes
-* Prevent extra whitespace for `<script>`-only templates
-* Correctly collapse empty elements
-* Improve directive support
+-   Remove .html from list of extensions
+-   Use `typescript` as parser to handle both JS and TS
+-   Add support for event modifiers
+-   Support Unicode content in `<script>` and `<style>` blocks
+-   Don't print children for empty elements
+-   Improve handling of text nodes
+-   Prevent extra whitespace for `<script>`-only templates
+-   Correctly collapse empty elements
+-   Improve directive support
 
 ## 0.4.2
 
-* Fix script + css and script + module printing
+-   Fix script + css and script + module printing
 
 ## 0.4.1
 
-* Print HTML last
+-   Print HTML last
 
 ## 0.4.0
 
-* Drop support for v2 and fully support v3
-* Make Prettier and Svelte peer deps
+-   Drop support for v2 and fully support v3
+-   Make Prettier and Svelte peer deps
diff --git a/README.md b/README.md
index 6af3e59..6c5c4b0 100644
--- a/README.md
+++ b/README.md
@@ -29,8 +29,14 @@ 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:
 ```
-prettier --write --plugin-search-dir=. ./**/*.html
+npx prettier --write --plugin-search-dir=. ./**/*.html
+```
+
+As part of your scripts in `package.json`:
+```
+"format": "prettier --write --plugin-search-dir=. ./**/*.html"
 ```
 
 If you want to customize some formatting behavior, see section "Options" below.
@@ -45,7 +51,7 @@ Make a `.prettierrc` file in your project directory and add your preferred [opti
 
 Sort order for `svelte:options`, scripts, markup, and styles.
 
-Format: join the keywords `options`, `scripts`, `markup`, `styles` with a `-` in the order you want.
+Format: join the keywords `options`, `scripts`, `markup`, `styles` with a `-` in the order you want; or `none` if you don't want Prettier to reorder anything.
 
 | Default                         | CLI Override                   | API Override                |
 | ------------------------------- | ------------------------------ | --------------------------- |
@@ -93,7 +99,7 @@ Example:
 
 > Deprecated since 2.5.0. Use Prettier 2.4.0 and [bracketSameLine](https://prettier.io/docs/en/options.html#bracket-line) instead.
 
-Put the `>` of a multiline element on a new line. Roughly the Svelte equivalent of the [jsxBracketSameLine](https://prettier.io/docs/en/options.html#jsx-brackets) rule. Setting this to `false` will have no effect for whitespace-sensitive tags (inline elements) when there's no whitespace between the `>` of the start tag and the inner content, or when there's no whitespace after the `>` of the end tag. You can read more about HTML whitespace sensitivity [here](https://prettier.io/blog/2018/11/07/1.15.0.html#whitespace-sensitive-formatting). You can adjust whitespace sensitivity through [this setting](https://prettier.io/docs/en/options.html#html-whitespace-sensitivity). 
+Put the `>` of a multiline element on a new line. Roughly the Svelte equivalent of the [jsxBracketSameLine](https://prettier.io/docs/en/options.html#jsx-brackets) rule. Setting this to `false` will have no effect for whitespace-sensitive tags (inline elements) when there's no whitespace between the `>` of the start tag and the inner content, or when there's no whitespace after the `>` of the end tag. You can read more about HTML whitespace sensitivity [here](https://prettier.io/blog/2018/11/07/1.15.0.html#whitespace-sensitive-formatting). You can adjust whitespace sensitivity through [this setting](https://prettier.io/docs/en/options.html#html-whitespace-sensitivity).
 
 Example:
 
@@ -151,6 +157,39 @@ Whether or not to indent the code inside `<script>` and `<style>` tags in Svelte
 
 ## Usage with Tailwind Prettier Plugin
 
-There's a Tailwind Prettier Plugin to format classes in a certain way. This plugin bundles `prettier-plugin-svelte`, so if you want to use the Tailwind plugin, uninstall `prettier-plugin-svelte` and use the Tailwind plugin instead. If you are using VS Code, make sure to have the Prettier extension installed and switch the default formatter for Svelte files to it.
+There is a [Tailwind Prettier Plugin](https://github.com/tailwindlabs/prettier-plugin-tailwindcss) to format classes in a certain way. This plugin must be loaded last, so if you want to use the Tailwind plugin, disable Prettier auto-loading and place `prettier-plugin-tailwindcss` in the end of the plugins array. If you are using VS Code, make sure to have the Prettier extension installed and switch the default formatter for Svelte files to it.
+
+```json5
+// .prettierrc
+{
+  // ..
+  "plugins": [
+    "prettier-plugin-svelte",
+    "prettier-plugin-tailwindcss" // MUST come last
+  ],
+  "pluginSearchDirs": false
+}
+```
 
 More info: https://github.com/tailwindlabs/prettier-plugin-tailwindcss#compatibility-with-other-prettier-plugins
+
+## FAQ
+
+### Why is the closing or opening tag (`>` or `<`) hugging the inner tag or text?
+
+If you are wondering why this code
+
+```html
+<span><span>assume very long text</span></span>
+```
+
+becomes this
+
+```html
+<span
+      ><span>assume very long text</span
+    ></span
+>
+```
+
+it's because of whitespsace sensitivity. For inline elements (`span`, `a`, etc) it makes a difference when rendered if there's a space (or newline) between them. Since we don't know if your slot inside your Svelte component is surrounded by inline elements, Svelte components are treated as such, too. You can adjust this whitespace sensitivity through [this setting](https://prettier.io/docs/en/options.html#html-whitespace-sensitivity). You can read more about HTML whitespace sensitivity [here](https://prettier.io/blog/2018/11/07/1.15.0.html#whitespace-sensitive-formatting).
diff --git a/package-lock.json b/package-lock.json
index ec6045f..d055e94 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
     "name": "prettier-plugin-svelte",
-    "version": "2.6.0",
+    "version": "2.9.0",
     "lockfileVersion": 2,
     "requires": true,
     "packages": {
         "": {
             "name": "prettier-plugin-svelte",
-            "version": "2.6.0",
+            "version": "2.9.0",
             "license": "MIT",
             "devDependencies": {
                 "@prettier/plugin-pug": "^1.16.0",
@@ -15,10 +15,10 @@
                 "@types/node": "^10.12.18",
                 "@types/prettier": "^2.4.1",
                 "ava": "3.15.0",
-                "prettier": "^2.4.1",
+                "prettier": "^2.7.1",
                 "rollup": "2.36.0",
                 "rollup-plugin-typescript": "1.0.1",
-                "svelte": "^3.47.0",
+                "svelte": "^3.54.0",
                 "ts-node": "^9.1.1",
                 "tslib": "^2.0.3",
                 "typescript": "4.1.3"
@@ -350,9 +350,9 @@
             }
         },
         "node_modules/ansi-align/node_modules/ansi-regex": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
-            "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+            "version": "4.1.1",
+            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
+            "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
             "dev": true,
             "engines": {
                 "node": ">=6"
@@ -400,9 +400,9 @@
             }
         },
         "node_modules/ansi-regex": {
-            "version": "5.0.0",
-            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
-            "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+            "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
             "dev": true,
             "engines": {
                 "node": ">=8"
@@ -2730,15 +2730,18 @@
             }
         },
         "node_modules/prettier": {
-            "version": "2.4.1",
-            "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz",
-            "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==",
+            "version": "2.7.1",
+            "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
+            "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
             "dev": true,
             "bin": {
                 "prettier": "bin-prettier.js"
             },
             "engines": {
                 "node": ">=10.13.0"
+            },
+            "funding": {
+                "url": "https://github.com/prettier/prettier?sponsor=1"
             }
         },
         "node_modules/pretty-ms": {
@@ -3361,9 +3364,9 @@
             }
         },
         "node_modules/svelte": {
-            "version": "3.47.0",
-            "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.47.0.tgz",
-            "integrity": "sha512-4JaJp3HEoTCGARRWZQIZDUanhYv0iyoHikklVHVLH9xFE9db22g4TDv7CPeNA8HD1JgjXI1vlhR1JZvvhaTu2Q==",
+            "version": "3.54.0",
+            "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.54.0.tgz",
+            "integrity": "sha512-tdrgeJU0hob0ZWAMoKXkhcxXA7dpTg6lZGxUeko5YqvPdJBiyRspGsCwV27kIrbrqPP2WUoSV9ca0gnLlw8YzQ==",
             "dev": true,
             "engines": {
                 "node": ">= 8"
@@ -3421,9 +3424,9 @@
             }
         },
         "node_modules/trim-off-newlines": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz",
-            "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=",
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.3.tgz",
+            "integrity": "sha512-kh6Tu6GbeSNMGfrrZh6Bb/4ZEHV1QlB4xNDBeog8Y9/QwFlKTRyWvY3Fs9tRDAMZliVUwieMgEdIeL/FtqjkJg==",
             "dev": true,
             "engines": {
                 "node": ">=0.10.0"
@@ -3964,9 +3967,9 @@
             },
             "dependencies": {
                 "ansi-regex": {
-                    "version": "4.1.0",
-                    "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
-                    "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+                    "version": "4.1.1",
+                    "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
+                    "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
                     "dev": true
                 },
                 "emoji-regex": {
@@ -4004,9 +4007,9 @@
             }
         },
         "ansi-regex": {
-            "version": "5.0.0",
-            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
-            "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+            "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
             "dev": true
         },
         "ansi-styles": {
@@ -5746,9 +5749,9 @@
             "dev": true
         },
         "prettier": {
-            "version": "2.4.1",
-            "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz",
-            "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==",
+            "version": "2.7.1",
+            "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
+            "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
             "dev": true
         },
         "pretty-ms": {
@@ -6224,9 +6227,9 @@
             }
         },
         "svelte": {
-            "version": "3.47.0",
-            "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.47.0.tgz",
-            "integrity": "sha512-4JaJp3HEoTCGARRWZQIZDUanhYv0iyoHikklVHVLH9xFE9db22g4TDv7CPeNA8HD1JgjXI1vlhR1JZvvhaTu2Q==",
+            "version": "3.54.0",
+            "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.54.0.tgz",
+            "integrity": "sha512-tdrgeJU0hob0ZWAMoKXkhcxXA7dpTg6lZGxUeko5YqvPdJBiyRspGsCwV27kIrbrqPP2WUoSV9ca0gnLlw8YzQ==",
             "dev": true
         },
         "temp-dir": {
@@ -6263,9 +6266,9 @@
             }
         },
         "trim-off-newlines": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz",
-            "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=",
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.3.tgz",
+            "integrity": "sha512-kh6Tu6GbeSNMGfrrZh6Bb/4ZEHV1QlB4xNDBeog8Y9/QwFlKTRyWvY3Fs9tRDAMZliVUwieMgEdIeL/FtqjkJg==",
             "dev": true
         },
         "ts-node": {
diff --git a/package.json b/package.json
index 9a7019e..08fd0a0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
     "name": "prettier-plugin-svelte",
-    "version": "2.6.0",
+    "version": "2.9.0",
     "description": "Svelte plugin for prettier",
     "main": "plugin.js",
     "files": [
@@ -34,10 +34,10 @@
         "@types/node": "^10.12.18",
         "@types/prettier": "^2.4.1",
         "ava": "3.15.0",
-        "prettier": "^2.4.1",
+        "prettier": "^2.7.1",
         "rollup": "2.36.0",
         "rollup-plugin-typescript": "1.0.1",
-        "svelte": "^3.47.0",
+        "svelte": "^3.54.0",
         "ts-node": "^9.1.1",
         "tslib": "^2.0.3",
         "typescript": "4.1.3"
diff --git a/src/embed.ts b/src/embed.ts
index 565c29e..a03f60d 100644
--- a/src/embed.ts
+++ b/src/embed.ts
@@ -1,8 +1,10 @@
 import { Doc, doc, FastPath, ParserOptions } from 'prettier';
 import { getText } from './lib/getText';
 import { snippedTagContentAttribute } from './lib/snipTagContent';
+import { isBracketSameLine } from './options';
 import { PrintFn } from './print';
 import { isLine, removeParentheses, trimRight } from './print/doc-helpers';
+import { groupConcat, printWithPrependedAttributeLine } from './print/helpers';
 import {
     getAttributeTextValue,
     getLeadingComment,
@@ -12,10 +14,10 @@ import {
     isTypeScript,
     printRaw,
 } from './print/node-helpers';
-import { ElementNode, Node } from './print/nodes';
+import { ElementNode, Node, ScriptNode, StyleNode } from './print/nodes';
 
 const {
-    builders: { concat, hardline, group, indent, literalline },
+    builders: { concat, hardline, softline, indent, dedent, literalline },
     utils: { removeLines },
 } = doc;
 
@@ -36,7 +38,14 @@ export function embed(
                 embeddedOptions.singleQuote = true;
             }
 
-            let docs = textToDoc(forceIntoExpression(getText(node, options)), embeddedOptions);
+            let docs = textToDoc(
+                forceIntoExpression(
+                    // If we have snipped content, it was done wrongly and we need to unsnip it.
+                    // This happens for example for {@html `<script>{foo}</script>`}
+                    getText(node, options, true),
+                ),
+                embeddedOptions,
+            );
             if (node.forceSingleLine) {
                 docs = removeLines(docs);
             }
@@ -45,7 +54,7 @@ export function embed(
             }
             return docs;
         } catch (e) {
-            return getText(node, options);
+            return getText(node, options, true);
         }
     }
 
@@ -181,7 +190,7 @@ function embedTag(
     isTopLevel: boolean,
     options: ParserOptions,
 ) {
-    const node: Node = path.getNode();
+    const node: ScriptNode | StyleNode | ElementNode = path.getNode();
     const content =
         tag === 'template' ? printRaw(node as ElementNode, text) : getSnippedContent(node);
     const previousComment = getLeadingComment(path);
@@ -201,21 +210,20 @@ function embedTag(
             : hardline
         : preformattedBody(content);
 
-    const attributes = concat(
-        path.map(
-            (childPath) =>
-                childPath.getNode().name !== snippedTagContentAttribute
-                    ? childPath.call(print)
-                    : '',
-            'attributes',
+    const openingTag = groupConcat([
+        '<',
+        tag,
+        indent(
+            groupConcat([
+                ...path.map(printWithPrependedAttributeLine(node, options, print), 'attributes'),
+                isBracketSameLine(options) ? '' : dedent(softline),
+            ]),
         ),
-    );
-
-    let result: Doc = group(
-        concat(['<', tag, indent(group(attributes)), '>', body, '</', tag, '>']),
-    );
+        '>',
+    ]);
+    let result = groupConcat([openingTag, body, '</', tag, '>']);
 
-    if (isTopLevel) {
+    if (isTopLevel && options.svelteSortOrder !== 'none') {
         // top level embedded nodes have been moved from their normal position in the
         // node tree. if there is a comment referring to it, it must be recreated at
         // the new position.
diff --git a/src/lib/extractAttributes.ts b/src/lib/extractAttributes.ts
index d46ca66..bd5208a 100644
--- a/src/lib/extractAttributes.ts
+++ b/src/lib/extractAttributes.ts
@@ -1,8 +1,8 @@
 import { AttributeNode, TextNode } from '../print/nodes';
 
 export function extractAttributes(html: string): AttributeNode[] {
-    const extractAttributesRegex = /<[a-z]+\s*(.*?)>/i;
-    const attributeRegex = /([^\s=]+)(?:=("|')(.*?)\2)?/gi;
+    const extractAttributesRegex = /<[a-z]+[\s\n]*([\s\S]*?)>/im;
+    const attributeRegex = /([^\s=]+)(?:=("|')([\s\S]*?)\2)?/gim;
 
     const [, attributesString] = html.match(extractAttributesRegex)!;
 
diff --git a/src/lib/getText.ts b/src/lib/getText.ts
index 3700076..82e2d14 100644
--- a/src/lib/getText.ts
+++ b/src/lib/getText.ts
@@ -1,15 +1,21 @@
 import { ParserOptions } from 'prettier';
 import { Node } from '../print/nodes';
+import { hasSnippedContent, unsnipContent } from './snipTagContent';
 
-export function getText(node: Node, options: ParserOptions) {
-    const leadingComments: Node[] = (node as any).leadingComments
-
-    return options.originalText.slice(
+export function getText(node: Node, options: ParserOptions, unsnip = false) {
+    const leadingComments: Node[] = (node as any).leadingComments;
+    const text = options.originalText.slice(
         options.locStart(
-            // if there are comments before the node they are not included 
+            // if there are comments before the node they are not included
             // in the `start` of the node itself
-            leadingComments && leadingComments[0] || node,
+            (leadingComments && leadingComments[0]) || node,
         ),
         options.locEnd(node),
     );
+
+    if (!unsnip || !hasSnippedContent(text)) {
+        return text;
+    }
+
+    return unsnipContent(text);
 }
diff --git a/src/options.ts b/src/options.ts
index eb3cef1..b22877a 100644
--- a/src/options.ts
+++ b/src/options.ts
@@ -48,6 +48,7 @@ export const options: Record<keyof PluginOptions, SupportOption> = {
             makeChoice('markup-scripts-styles-options'),
             makeChoice('styles-markup-scripts-options'),
             makeChoice('styles-scripts-markup-options'),
+            makeChoice('none'),
             // Deprecated, keep in 2.x for backwards-compatibility. svelte:options will be moved to the top
             makeChoice('scripts-markup-styles'),
             makeChoice('scripts-styles-markup'),
@@ -114,6 +115,7 @@ export type SortOrder =
     | 'markup-scripts-styles-options'
     | 'styles-markup-scripts-options'
     | 'styles-scripts-markup-options'
+    | 'none'
     | DeprecatedSortOrder;
 
 export type DeprecatedSortOrder =
@@ -129,6 +131,10 @@ export type SortOrderPart = 'scripts' | 'markup' | 'styles' | 'options';
 const sortOrderSeparator = '-';
 
 export function parseSortOrder(sortOrder: SortOrder): SortOrderPart[] {
+    if (sortOrder === 'none') {
+        return [];
+    }
+
     const order = sortOrder.split(sortOrderSeparator) as SortOrderPart[];
     // For backwards compatibility: Add options to beginning if not present
     if (!order.includes('options')) {
diff --git a/src/print/helpers.ts b/src/print/helpers.ts
index 35192da..904d03c 100644
--- a/src/print/helpers.ts
+++ b/src/print/helpers.ts
@@ -1,6 +1,23 @@
-import { ASTNode, Node } from './nodes';
-import { Doc, FastPath } from 'prettier';
+import {
+    ASTNode,
+    AttributeNode,
+    BodyNode,
+    ElementNode,
+    HeadNode,
+    InlineComponentNode,
+    Node,
+    OptionsNode,
+    ScriptNode,
+    SlotNode,
+    SlotTemplateNode,
+    StyleNode,
+    TitleNode,
+    WindowNode,
+} from './nodes';
+import { Doc, doc, FastPath, ParserOptions } from 'prettier';
 import { formattableAttributes } from '../lib/elements';
+import { PrintFn } from '.';
+import { snippedTagContentAttribute } from '../lib/snipTagContent';
 
 /**
  * Determines whether or not given node
@@ -48,3 +65,59 @@ export function replaceEndOfLineWith(text: string, replacement: Doc) {
     }
     return parts;
 }
+
+export function groupConcat(contents: doc.builders.Doc[]): doc.builders.Doc {
+    const { concat, group } = doc.builders;
+    return group(concat(contents));
+}
+
+export function getAttributeLine(
+    node:
+        | ElementNode
+        | InlineComponentNode
+        | SlotNode
+        | WindowNode
+        | HeadNode
+        | TitleNode
+        | StyleNode
+        | ScriptNode
+        | BodyNode
+        | OptionsNode
+        | SlotTemplateNode,
+    options: ParserOptions,
+) {
+    const { hardline, line } = doc.builders;
+    const hasThisBinding =
+        (node.type === 'InlineComponent' && !!node.expression) ||
+        (node.type === 'Element' && !!node.tag);
+
+    const attributes = (node.attributes as Array<AttributeNode>).filter(
+        (attribute) => attribute.name !== snippedTagContentAttribute,
+    );
+    return options.singleAttributePerLine &&
+        (attributes.length > 1 || (attributes.length && hasThisBinding))
+        ? hardline
+        : line;
+}
+
+export function printWithPrependedAttributeLine(
+    node:
+        | ElementNode
+        | InlineComponentNode
+        | SlotNode
+        | WindowNode
+        | HeadNode
+        | TitleNode
+        | StyleNode
+        | ScriptNode
+        | BodyNode
+        | OptionsNode
+        | SlotTemplateNode,
+    options: ParserOptions,
+    print: PrintFn,
+): PrintFn {
+    return (path) =>
+        path.getNode().name !== snippedTagContentAttribute
+            ? doc.builders.concat([getAttributeLine(node, options), path.call(print)])
+            : '';
+}
diff --git a/src/print/index.ts b/src/print/index.ts
index 4c9151c..66514be 100644
--- a/src/print/index.ts
+++ b/src/print/index.ts
@@ -5,7 +5,15 @@ import { getText } from '../lib/getText';
 import { hasSnippedContent, unsnipContent } from '../lib/snipTagContent';
 import { isBracketSameLine, parseSortOrder, SortOrderPart } from '../options';
 import { isEmptyDoc, isLine, trim, trimRight } from './doc-helpers';
-import { flatten, isASTNode, isPreTagContent, replaceEndOfLineWith } from './helpers';
+import {
+    flatten,
+    getAttributeLine,
+    groupConcat,
+    isASTNode,
+    isPreTagContent,
+    printWithPrependedAttributeLine,
+    replaceEndOfLineWith,
+} from './helpers';
 import {
     checkWhitespaceAtEndOfSvelteBlock,
     checkWhitespaceAtStartOfSvelteBlock,
@@ -36,6 +44,7 @@ import {
     isIgnoreStartDirective,
     isIgnoreEndDirective,
     isNodeTopLevelHTML,
+    getChildren,
 } from './node-helpers';
 import {
     ASTNode,
@@ -78,10 +87,6 @@ let ignoreNext = false;
 let ignoreRange = false;
 let svelteOptionsDoc: Doc | undefined;
 
-function groupConcat(contents: doc.builders.Doc[]): doc.builders.Doc {
-    return group(concat(contents));
-}
-
 export function print(path: FastPath, options: ParserOptions, print: PrintFn): Doc {
     const bracketSameLine = isBracketSameLine(options);
 
@@ -190,21 +195,27 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
                 node.name === 'template' && !isNodeSupportedLanguage(node)
             );
             const isEmpty = node.children.every((child) => isEmptyTextNode(child));
+            const isDoctypeTag = node.name.toUpperCase() === '!DOCTYPE';
 
             const isSelfClosingTag =
                 isEmpty &&
                 (!options.svelteStrictMode ||
                     node.type !== 'Element' ||
-                    selfClosingTags.indexOf(node.name) !== -1);
+                    selfClosingTags.indexOf(node.name) !== -1 ||
+                    isDoctypeTag);
 
             // Order important: print attributes first
-            const attributes = path.map((childPath) => childPath.call(print), 'attributes');
+            const attributes = path.map(
+                printWithPrependedAttributeLine(node, options, print),
+                'attributes',
+            );
+            const attributeLine = getAttributeLine(node, options);
             const possibleThisBinding =
                 node.type === 'InlineComponent' && node.expression
-                    ? concat([line, 'this=', ...printJsExpression()])
+                    ? concat([attributeLine, 'this=', ...printJsExpression()])
                     : node.type === 'Element' && node.tag
                     ? concat([
-                          line,
+                          attributeLine,
                           'this=',
                           ...(typeof node.tag === 'string'
                               ? [`"${node.tag}"`]
@@ -232,11 +243,11 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
                         groupConcat([
                             possibleThisBinding,
                             ...attributes,
-                            bracketSameLine ? '' : dedent(line),
+                            bracketSameLine || isDoctypeTag ? '' : dedent(line),
                         ]),
                     ),
 
-                    ...[bracketSameLine ? ' ' : '', `/>`],
+                    ...[bracketSameLine && !isDoctypeTag ? ' ' : '', `${isDoctypeTag ? '' : '/'}>`],
                 ]);
             }
 
@@ -378,15 +389,24 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
             ]);
         }
         case 'Options':
-            throw new Error('Options tags should have been handled by prepareChildren');
+            if (options.svelteSortOrder !== 'none') {
+                throw new Error('Options tags should have been handled by prepareChildren');
+            }
+        // else fall through to Body
         case 'Body':
             return groupConcat([
                 '<',
                 node.name,
-
-                indent(groupConcat(path.map((childPath) => childPath.call(print), 'attributes'))),
-
-                ' />',
+                indent(
+                    groupConcat([
+                        ...path.map(
+                            printWithPrependedAttributeLine(node, options, print),
+                            'attributes',
+                        ),
+                        bracketSameLine ? '' : dedent(line),
+                    ]),
+                ),
+                ...[bracketSameLine ? ' ' : '', '/>'],
             ]);
         case 'Identifier':
             return node.name;
@@ -396,23 +416,23 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
         case 'Attribute': {
             if (isOrCanBeConvertedToShorthand(node)) {
                 if (options.svelteStrictMode) {
-                    return concat([line, node.name, '="{', node.name, '}"']);
+                    return concat([node.name, '="{', node.name, '}"']);
                 } else if (options.svelteAllowShorthand) {
-                    return concat([line, '{', node.name, '}']);
+                    return concat(['{', node.name, '}']);
                 } else {
-                    return concat([line, node.name, '={', node.name, '}']);
+                    return concat([node.name, '={', node.name, '}']);
                 }
             } else {
                 if (node.value === true) {
-                    return concat([line, node.name]);
+                    return concat([node.name]);
                 }
 
                 const quotes = !isLoneMustacheTag(node.value) || options.svelteStrictMode;
                 const attrNodeValue = printAttributeNodeValue(path, print, quotes, node);
                 if (quotes) {
-                    return concat([line, node.name, '=', '"', attrNodeValue, '"']);
+                    return concat([node.name, '=', '"', attrNodeValue, '"']);
                 } else {
-                    return concat([line, node.name, '=', attrNodeValue]);
+                    return concat([node.name, '=', attrNodeValue]);
                 }
             }
         }
@@ -520,6 +540,17 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
                     ]),
                     path.call(print, 'then'),
                 );
+            } else if (!hasPendingBlock && hasCatchBlock) {
+                block.push(
+                    groupConcat([
+                        '{#await ',
+                        printSvelteBlockJS(path, print, 'expression'),
+                        ' catch',
+                        expandNode(node.error),
+                        '}',
+                    ]),
+                    path.call(print, 'catch'),
+                );
             } else {
                 block.push(
                     groupConcat(['{#await ', printSvelteBlockJS(path, print, 'expression'), '}']),
@@ -537,7 +568,7 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
                 }
             }
 
-            if (hasCatchBlock) {
+            if ((hasPendingBlock || hasThenBlock) && hasCatchBlock) {
                 block.push(
                     groupConcat(['{:catch', expandNode(node.error), '}']),
                     path.call(print, 'catch'),
@@ -566,7 +597,6 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
             return printSvelteBlockChildren(path, print, options);
         case 'EventHandler':
             return concat([
-                line,
                 'on:',
                 node.name,
                 node.modifiers && node.modifiers.length
@@ -576,47 +606,54 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
             ]);
         case 'Binding':
             return concat([
-                line,
                 'bind:',
                 node.name,
-                node.expression.type === 'Identifier' && node.expression.name === node.name
+                node.expression.type === 'Identifier' &&
+                node.expression.name === node.name &&
+                options.svelteAllowShorthand &&
+                !options.svelteStrictMode
                     ? ''
                     : concat(['=', ...printJsExpression()]),
             ]);
         case 'Class':
             return concat([
-                line,
                 'class:',
                 node.name,
-                node.expression.type === 'Identifier' && node.expression.name === node.name
+                node.expression.type === 'Identifier' &&
+                node.expression.name === node.name &&
+                options.svelteAllowShorthand &&
+                !options.svelteStrictMode
                     ? ''
                     : concat(['=', ...printJsExpression()]),
             ]);
         case 'StyleDirective':
-            if (isOrCanBeConvertedToShorthand(node)) {
+            const prefix = [
+                'style:',
+                node.name,
+                node.modifiers && node.modifiers.length
+                    ? concat(['|', join('|', node.modifiers)])
+                    : '',
+            ];
+
+            if (isOrCanBeConvertedToShorthand(node) || node.value === true) {
                 if (options.svelteStrictMode) {
-                    return concat([line, 'style:', node.name, '="{', node.name, '}"']);
+                    return concat([...prefix, '="{', node.name, '}"']);
                 } else if (options.svelteAllowShorthand) {
-                    return concat([line, 'style:', node.name]);
+                    return concat([...prefix]);
                 } else {
-                    return concat([line, 'style:', node.name, '={', node.name, '}']);
+                    return concat([...prefix, '={', node.name, '}']);
                 }
             } else {
-                if (node.value === true) {
-                    return concat([line, 'style:', node.name]);
-                }
-
                 const quotes = !isLoneMustacheTag(node.value) || options.svelteStrictMode;
                 const attrNodeValue = printAttributeNodeValue(path, print, quotes, node);
                 if (quotes) {
-                    return concat([line, 'style:', node.name, '=', '"', attrNodeValue, '"']);
+                    return concat([...prefix, '=', '"', attrNodeValue, '"']);
                 } else {
-                    return concat([line, 'style:', node.name, '=', attrNodeValue]);
+                    return concat([...prefix, '=', attrNodeValue]);
                 }
             }
         case 'Let':
             return concat([
-                line,
                 'let:',
                 node.name,
                 // shorthand let directives have `null` expressions
@@ -634,7 +671,7 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
                 '}',
             ]);
         case 'Ref':
-            return concat([line, 'ref:', node.name]);
+            return concat(['ref:', node.name]);
         case 'Comment': {
             const nodeAfterComment = getNextNode(path);
 
@@ -662,7 +699,6 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
         case 'Transition':
             const kind = node.intro && node.outro ? 'transition' : node.intro ? 'in' : 'out';
             return concat([
-                line,
                 kind,
                 ':',
                 node.name,
@@ -673,14 +709,12 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
             ]);
         case 'Action':
             return concat([
-                line,
                 'use:',
                 node.name,
                 node.expression ? concat(['=', ...printJsExpression()]) : '',
             ]);
         case 'Animation':
             return concat([
-                line,
                 'animate:',
                 node.name,
                 node.expression ? concat(['=', ...printJsExpression()]) : '',
@@ -692,12 +726,7 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
                 '}',
             ]);
         case 'Spread':
-            return concat([
-                line,
-                '{...',
-                printJS(path, print, false, false, false, 'expression'),
-                '}',
-            ]);
+            return concat(['{...', printJS(path, print, false, false, false, 'expression'), '}']);
         case 'ConstTag':
             return concat([
                 '{@const ',
@@ -716,6 +745,36 @@ function printTopLevelParts(
     path: FastPath<any>,
     print: PrintFn,
 ): Doc {
+    if (options.svelteSortOrder === 'none') {
+        const topLevelPartsByEnd: Record<number, any> = {};
+
+        if (n.module) {
+            n.module.type = 'Script';
+            n.module.attributes = extractAttributes(getText(n.module, options));
+            topLevelPartsByEnd[n.module.end] = n.module;
+        }
+        if (n.instance) {
+            n.instance.type = 'Script';
+            n.instance.attributes = extractAttributes(getText(n.instance, options));
+            topLevelPartsByEnd[n.instance.end] = n.instance;
+        }
+        if (n.css) {
+            n.css.type = 'Style';
+            n.css.content.type = 'StyleProgram';
+            topLevelPartsByEnd[n.css.end] = n.css;
+        }
+
+        const children = getChildren(n.html);
+        for (let i = 0; i < children.length; i++) {
+            const node = children[i];
+            if (topLevelPartsByEnd[node.start]) {
+                children.splice(i, 0, topLevelPartsByEnd[node.start]);
+                delete topLevelPartsByEnd[node.start];
+            }
+        }
+        return path.call(print, 'html');
+    }
+
     const parts: Record<SortOrderPart, Doc[]> = {
         options: [],
         scripts: [],
@@ -850,7 +909,7 @@ function printChildren(path: FastPath, print: PrintFn, options: ParserOptions):
         return concat(path.map(print, 'children'));
     }
 
-    const childNodes: Node[] = prepareChildren(path.getValue().children, path, print);
+    const childNodes: Node[] = prepareChildren(path.getValue().children, path, print, options);
     // modify original array because it's accessed later through map(print, 'children', idx)
     path.getValue().children = childNodes;
     if (childNodes.length === 0) {
@@ -997,9 +1056,15 @@ function printChildren(path: FastPath, print: PrintFn, options: ParserOptions):
  * separately to reorder it as configured. The comment above it should be moved with it.
  * Do that here.
  */
-function prepareChildren(children: Node[], path: FastPath, print: PrintFn): Node[] {
+function prepareChildren(
+    children: Node[],
+    path: FastPath,
+    print: PrintFn,
+    options: ParserOptions,
+): Node[] {
     let svelteOptionsComment: Doc | undefined;
     const childrenWithoutOptions = [];
+    const bracketSameLine = isBracketSameLine(options);
 
     for (let idx = 0; idx < children.length; idx++) {
         const currentChild = children[idx];
@@ -1012,16 +1077,18 @@ function prepareChildren(children: Node[], path: FastPath, print: PrintFn): Node
             continue;
         }
 
-        if (isCommentFollowedByOptions(currentChild, idx)) {
-            svelteOptionsComment = printComment(currentChild);
-            const nextChild = children[idx + 1];
-            idx += nextChild && isEmptyTextNode(nextChild) ? 1 : 0;
-            continue;
-        }
+        if (options.svelteSortOrder !== 'none') {
+            if (isCommentFollowedByOptions(currentChild, idx)) {
+                svelteOptionsComment = printComment(currentChild);
+                const nextChild = children[idx + 1];
+                idx += nextChild && isEmptyTextNode(nextChild) ? 1 : 0;
+                continue;
+            }
 
-        if (currentChild.type === 'Options') {
-            printSvelteOptions(currentChild, idx, path, print);
-            continue;
+            if (currentChild.type === 'Options') {
+                printSvelteOptions(currentChild, idx, path, print);
+                continue;
+            }
         }
 
         childrenWithoutOptions.push(currentChild);
@@ -1055,10 +1122,18 @@ function prepareChildren(children: Node[], path: FastPath, print: PrintFn): Node
             groupConcat([
                 '<',
                 node.name,
-
-                indent(groupConcat(path.map(print, 'children', idx, 'attributes'))),
-
-                ' />',
+                indent(
+                    groupConcat([
+                        ...path.map(
+                            printWithPrependedAttributeLine(node, options, print),
+                            'children',
+                            idx,
+                            'attributes',
+                        ),
+                        bracketSameLine ? '' : dedent(line),
+                    ]),
+                ),
+                ...[bracketSameLine ? ' ' : '', '/>'],
             ]),
             hardline,
         ]);
diff --git a/src/print/nodes.ts b/src/print/nodes.ts
index cbdea26..13dcbb0 100644
--- a/src/print/nodes.ts
+++ b/src/print/nodes.ts
@@ -127,6 +127,7 @@ export interface StyleDirectiveNode extends BaseNode {
     type: 'StyleDirective';
     name: string;
     value: Node[] | true;
+    modifiers?: string[];
 }
 
 export interface LetNode extends BaseNode {


Test patch:
diff --git a/test/formatting/samples/single-attribute-per-line/input.html b/test/formatting/samples/single-attribute-per-line/input.html
new file mode 100644
index 0000000..971d726
--- /dev/null
+++ b/test/formatting/samples/single-attribute-per-line/input.html
@@ -0,0 +1,38 @@
+<svelte:options immutable={true} accessors={true} />
+
+<script type="typescript" context="module">
+  const hi = "";
+</script>
+
+<script
+  type="typescript"
+>
+  const hi = "";
+</script>
+
+<div id="x" class="y" animate:flip use:autofocus {...props}>Copy</div>
+
+<div
+  id="x">Copy</div>
+
+<span id="x" class="y">Copy</span>
+
+<div id="x" class:y={true} style:marginLeft="4px" on:click={onClick} />
+
+<svelte:body on:mouseenter={handleMouseenter} on:mouseleave={handleMouseleave} />
+
+<svelte:component this={component} foo={bar} />
+
+<svelte:component
+  this={component}
+/>
+
+<svelte:element this={tag} on:click={handler}>
+  Foo
+</svelte:element>
+
+<svelte:fragment slot="named" let:foo>
+  <p>hi</p>
+</svelte:fragment>
+
+<svelte:window on:event={handler} bind:prop={value} />
diff --git a/test/formatting/samples/single-attribute-per-line/options.json b/test/formatting/samples/single-attribute-per-line/options.json
new file mode 100644
index 0000000..c4d8ac5
--- /dev/null
+++ b/test/formatting/samples/single-attribute-per-line/options.json
@@ -0,0 +1,3 @@
+{
+    "singleAttributePerLine": true
+}
diff --git a/test/formatting/samples/single-attribute-per-line/output.html b/test/formatting/samples/single-attribute-per-line/output.html
new file mode 100644
index 0000000..129f9fa
--- /dev/null
+++ b/test/formatting/samples/single-attribute-per-line/output.html
@@ -0,0 +1,70 @@
+<svelte:options
+    immutable={true}
+    accessors={true}
+/>
+
+<script
+    type="typescript"
+    context="module"
+>
+    const hi = "";
+</script>
+
+<script type="typescript">
+    const hi = "";
+</script>
+
+<div
+    id="x"
+    class="y"
+    animate:flip
+    use:autofocus
+    {...props}
+>
+    Copy
+</div>
+
+<div id="x">Copy</div>
+
+<span
+    id="x"
+    class="y">Copy</span
+>
+
+<div
+    id="x"
+    class:y={true}
+    style:marginLeft="4px"
+    on:click={onClick}
+/>
+
+<svelte:body
+    on:mouseenter={handleMouseenter}
+    on:mouseleave={handleMouseleave}
+/>
+
+<svelte:component
+    this={component}
+    foo={bar}
+/>
+
+<svelte:component this={component} />
+
+<svelte:element
+    this={tag}
+    on:click={handler}
+>
+    Foo
+</svelte:element>
+
+<svelte:fragment
+    slot="named"
+    let:foo
+>
+    <p>hi</p>
+</svelte:fragment>
+
+<svelte:window
+    on:event={handler}
+    bind:prop={value}
+/>
diff --git a/test/formatting/samples/strict-mode-false/input.html b/test/formatting/samples/strict-mode-false/input.html
new file mode 100644
index 0000000..a73d77a
--- /dev/null
+++ b/test/formatting/samples/strict-mode-false/input.html
@@ -0,0 +1,14 @@
+<input value />
+<input value="string" />
+<input {value} />
+<input value={value} />
+<input value="{value}" />
+<input bind:value />
+<input bind:value={value} />
+<input bind:value="{value}" />
+<input class:value />
+<input class:value={value} />
+<input class:value="{value}" />
+<input style:value />
+<input style:value={value} />
+<input style:value="{value}" />
diff --git a/test/formatting/samples/strict-mode-false/output.html b/test/formatting/samples/strict-mode-false/output.html
new file mode 100644
index 0000000..5b52393
--- /dev/null
+++ b/test/formatting/samples/strict-mode-false/output.html
@@ -0,0 +1,14 @@
+<input value />
+<input value="string" />
+<input {value} />
+<input {value} />
+<input {value} />
+<input bind:value />
+<input bind:value />
+<input bind:value />
+<input class:value />
+<input class:value />
+<input class:value />
+<input style:value />
+<input style:value />
+<input style:value />
diff --git a/test/formatting/samples/strict-mode-true/input.html b/test/formatting/samples/strict-mode-true/input.html
index 620e528..a73d77a 100644
--- a/test/formatting/samples/strict-mode-true/input.html
+++ b/test/formatting/samples/strict-mode-true/input.html
@@ -3,3 +3,12 @@
 <input {value} />
 <input value={value} />
 <input value="{value}" />
+<input bind:value />
+<input bind:value={value} />
+<input bind:value="{value}" />
+<input class:value />
+<input class:value={value} />
+<input class:value="{value}" />
+<input style:value />
+<input style:value={value} />
+<input style:value="{value}" />
diff --git a/test/formatting/samples/strict-mode-true/output.html b/test/formatting/samples/strict-mode-true/output.html
index c293a2a..44757b5 100644
--- a/test/formatting/samples/strict-mode-true/output.html
+++ b/test/formatting/samples/strict-mode-true/output.html
@@ -3,3 +3,12 @@
 <input value="{value}" />
 <input value="{value}" />
 <input value="{value}" />
+<input bind:value="{value}" />
+<input bind:value="{value}" />
+<input bind:value="{value}" />
+<input class:value="{value}" />
+<input class:value="{value}" />
+<input class:value="{value}" />
+<input style:value="{value}" />
+<input style:value="{value}" />
+<input style:value="{value}" />
diff --git a/test/printer/samples/allow-shorthand-false.html b/test/printer/samples/allow-shorthand-false.html
index c39f851..98523e6 100644
--- a/test/printer/samples/allow-shorthand-false.html
+++ b/test/printer/samples/allow-shorthand-false.html
@@ -1,3 +1,9 @@
 <input type="text" value={value} />
 
 <input type="text" data={data} />
+
+<input type="text" bind:value={value} />
+
+<input type="text" class:value={value} />
+
+<input type="text" style:value={value} />
diff --git a/test/printer/samples/await-catch-without-pending.html b/test/printer/samples/await-catch-without-pending.html
new file mode 100644
index 0000000..841f620
--- /dev/null
+++ b/test/printer/samples/await-catch-without-pending.html
@@ -0,0 +1,1 @@
+{#await thePromise catch theCatch}the value is {theCatch}{/await}
diff --git a/test/printer/samples/doctype.html b/test/printer/samples/doctype.html
new file mode 100644
index 0000000..0e76edd
--- /dev/null
+++ b/test/printer/samples/doctype.html
@@ -0,0 +1,1 @@
+<!DOCTYPE html>
diff --git a/test/printer/samples/no-tag-snippings.html b/test/printer/samples/no-tag-snippings.html
new file mode 100644
index 0000000..d60d00a
--- /dev/null
+++ b/test/printer/samples/no-tag-snippings.html
@@ -0,0 +1,22 @@
+<svelte:head>
+    <script type="application/ld+json">
+        {
+          "@context": "https://schema.org",
+          "@type": "etc..."
+        }
+    </script>
+    {@html `<style>${getCssText()}</style>`}
+</svelte:head>
+
+<pre class="p-2">
+    {`<div>
+        <span>Hello</span>
+        <span>World</span>
+      </div>
+
+      <style lang="postcss">
+        span {
+          @apply text-red-500;
+        }
+      </style>`}
+</pre>
diff --git a/test/printer/samples/single-attribute-per-line-bracket-no-new-line.html b/test/printer/samples/single-attribute-per-line-bracket-no-new-line.html
new file mode 100644
index 0000000..c4aa1b2
--- /dev/null
+++ b/test/printer/samples/single-attribute-per-line-bracket-no-new-line.html
@@ -0,0 +1,58 @@
+<svelte:options
+    immutable={true}
+    accessors={true} />
+
+<script
+    type="typescript"
+    context="module">
+    const hi = "";
+</script>
+
+<script type="typescript">
+    const hi = "";
+</script>
+
+<div
+    id="x"
+    class="y"
+    animate:flip
+    use:autofocus
+    {...props}>
+    Copy
+</div>
+
+<div id="x">Copy</div>
+
+<span
+    id="x"
+    class="y">Copy</span>
+
+<div
+    id="x"
+    class:y={true}
+    style:marginLeft="4px"
+    on:click={onClick} />
+
+<svelte:body
+    on:mouseenter={handleMouseenter}
+    on:mouseleave={handleMouseleave} />
+
+<svelte:component
+    this={component}
+    foo={bar} />
+
+<svelte:component this={component} />
+
+<svelte:element
+    this={tag}
+    on:click={handler}>
+    Foo
+</svelte:element>
+
+<svelte:fragment
+    slot="named"
+    let:foo><p>hi</p></svelte:fragment>
+
+<svelte:window
+    on:event={handler}
+    bind:prop={value} />
diff --git a/test/printer/samples/single-attribute-per-line-bracket-no-new-line.options.json b/test/printer/samples/single-attribute-per-line-bracket-no-new-line.options.json
new file mode 100644
index 0000000..fae8329
--- /dev/null
+++ b/test/printer/samples/single-attribute-per-line-bracket-no-new-line.options.json
@@ -0,0 +1,4 @@
+{
+    "singleAttributePerLine": true,
+    "bracketSameLine": true
+}
diff --git a/test/printer/samples/single-attribute-per-line.html b/test/printer/samples/single-attribute-per-line.html
new file mode 100644
index 0000000..28ed30e
--- /dev/null
+++ b/test/printer/samples/single-attribute-per-line.html
@@ -0,0 +1,68 @@
+<svelte:options
+    immutable={true}
+    accessors={true}
+/>
+
+<script
+    type="typescript"
+    context="module"
+>
+    const hi = "";
+</script>
+
+<script type="typescript">
+    const hi = "";
+</script>
+
+<div
+    id="x"
+    class="y"
+    animate:flip
+    use:autofocus
+    {...props}
+>
+    Copy
+</div>
+
+<div id="x">Copy</div>
+
+<span
+    id="x"
+    class="y">Copy</span
+>
+
+<div
+    id="x"
+    class:y={true}
+    style:marginLeft="4px"
+    on:click={onClick}
+/>
+
+<svelte:body
+    on:mouseenter={handleMouseenter}
+    on:mouseleave={handleMouseleave}
+/>
+
+<svelte:component
+    this={component}
+    foo={bar}
+/>
+
+<svelte:component this={component} />
+
+<svelte:element
+    this={tag}
+    on:click={handler}
+>
+    Foo
+</svelte:element>
+
+<svelte:fragment
+    slot="named"
+    let:foo><p>hi</p></svelte:fragment
+>
+
+<svelte:window
+    on:event={handler}
+    bind:prop={value}
+/>
diff --git a/test/printer/samples/single-attribute-per-line.options.json b/test/printer/samples/single-attribute-per-line.options.json
new file mode 100644
index 0000000..c4d8ac5
--- /dev/null
+++ b/test/printer/samples/single-attribute-per-line.options.json
@@ -0,0 +1,3 @@
+{
+    "singleAttributePerLine": true
+}
diff --git a/test/printer/samples/sort-order-none.html b/test/printer/samples/sort-order-none.html
new file mode 100644
index 0000000..ada7724
--- /dev/null
+++ b/test/printer/samples/sort-order-none.html
@@ -0,0 +1,23 @@
+<h1>Hello {name}!</h1>
+
+<svelte:options />
+
+<p>yeah why not</p>
+
+<script>
+    const name = "world";
+</script>
+
+<script context="module">
+    const name1 = "world";
+</script>
+
+<p>I hope noone orders them like this</p>
+
+<style>
+    h1 {
+        color: red;
+    }
+</style>
+
+<p>I really do</p>
diff --git a/test/printer/samples/sort-order-none.options.json b/test/printer/samples/sort-order-none.options.json
new file mode 100644
index 0000000..fd6e47a
--- /dev/null
+++ b/test/printer/samples/sort-order-none.options.json
@@ -0,0 +1,3 @@
+{
+    "svelteSortOrder": "none"
+}
diff --git a/test/printer/samples/sort-order-none2.html b/test/printer/samples/sort-order-none2.html
new file mode 100644
index 0000000..df86335
--- /dev/null
+++ b/test/printer/samples/sort-order-none2.html
@@ -0,0 +1,23 @@
+<script>
+    const name = "world";
+</script>
+
+<h1>Hello {name}!</h1>
+
+<svelte:options />
+
+<p>yeah why not</p>
+<!-- hi -->
+<script context="module">
+    const name1 = "world";
+</script>
+
+<p>I hope noone orders them like this</p>
+
+<style>
+    h1 {
+        color: red;
+    }
+</style>
+
+<p>I really do</p>
diff --git a/test/printer/samples/sort-order-none2.options.json b/test/printer/samples/sort-order-none2.options.json
new file mode 100644
index 0000000..fd6e47a
--- /dev/null
+++ b/test/printer/samples/sort-order-none2.options.json
@@ -0,0 +1,3 @@
+{
+    "svelteSortOrder": "none"
+}
diff --git a/test/printer/samples/style-directive.html b/test/printer/samples/style-directive.html
index 792ee27..c9faea9 100644
--- a/test/printer/samples/style-directive.html
+++ b/test/printer/samples/style-directive.html
@@ -5,3 +5,11 @@
 <div style:background="prefix{color}" />
 <div style:background={`prefix${color}`} />
 <div style:background />
+
+<div style:background|important="green" />
+<div style:background|important={color} />
+<div style:background|important="prefix{color}suffix" />
+<div style:background|important="{color}suffix" />
+<div style:background|important="prefix{color}" />
+<div style:background|important={`prefix${color}`} />
+<div style:background|important />