Repository: sveltejs/prettier-plugin-svelte (ts)

Issue:
removing beginning `s` in text/html, with `<style />`
moved here from: https://github.com/sveltejs/language-tools/issues/324

<!-- Before you submit a bug, please make sure that:
- you don't have   "files.associations": {"*.svelte": "html"  }   inside your VSCode settings (if you can't remember ever doing that, you don't have that)
- you are using Svelte for Vscode (NOT the old "Svelte" by James Birtles) and have disabled all other Svelte-related extensions to reproduce the bug
- if it's a preprocessor related bug like "can't use typescript", did you setup `svelte-preprocess` and/or `svelte.config.js`? See the docs for more info.
-->

**Describe the bug**
This or `prettier`, is removing starting works with beginning `s`, like `sweet`, `Sweet`, `sssweet`, after saving.

**To Reproduce**
Steps to reproduce the behavior:

`App.svelte`
```
<style>

</style>

sssweet
```

get's turned into: (after saving, see screenshot)

```
<style>

</style>

weet
```

**Expected behavior**
It should keep the `sssweet`

**Screenshots**
![2020-07-19_21-20-22](https://user-images.githubusercontent.com/1171187/87890977-7f258000-ca06-11ea-8c0e-ccb0bb71cdbd.gif)


**System (please complete the following information):**
 - OS: Windows 10
 - IDE: VSCode
 - Plugin/Package: "Svelte for VSCode", "Prettier"

**Additional context**
Strange.

Pull request description:
Incorrectly escaped regexp broke style tags followed by "s"
If there was the letter "s" after a `<style>` block, it would be trimmed.

Because the regexp is inside backticks `\s` will be interpreted as just an "s" with an unnecessary quote. It needs double-quoting for the regexp to receive it as `\s` (note that the same does not apply for `\n` because it's just turned into a newline by the backticks and passed as such to regexp which is fine).

Compare

```
> ' s'.match(new RegExp('\s'))
[ 's', index: 1, input: ' s\t', groups: undefined ]
> ' s'.match(new RegExp('\\s'))
[ ' ', index: 0, input: ' s\t', groups: undefined ]
```

Fixes #118 

Patch:
diff --git a/.gitignore b/.gitignore
index 4bf4be0..5f34e42 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 node_modules
 .vscode
+.history
 plugin.js
 plugin.js.map
diff --git a/package-lock.json b/package-lock.json
index 16d1540..4cb0c0b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -412,9 +412,9 @@
             "dev": true
         },
         "@types/prettier": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.0.0.tgz",
-            "integrity": "sha512-/rM+sWiuOZ5dvuVzV37sUuklsbg+JPOP8d+nNFlo2ZtfpzPiPvh1/gc8liWOLBqe+sR+ZM7guPaIcTt6UZTo7Q==",
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.0.2.tgz",
+            "integrity": "sha512-IkVfat549ggtkZUthUzEX49562eGikhSYeVGX97SkMFn+sTZrgRewXjQ4tPKFPCykZHkX1Zfd9OoELGqKU2jJA==",
             "dev": true
         },
         "acorn": {
@@ -3530,9 +3530,9 @@
             "dev": true
         },
         "prettier": {
-            "version": "2.0.5",
-            "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz",
-            "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==",
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.0.tgz",
+            "integrity": "sha512-lz28cCbA1cDFHVuY8vvj6QuqOwIpyIfPUYkSl8AZ/vxH8qBXMMjE2knfLHCrZCmUsK/H1bg1P0tOo0dJkTJHvw==",
             "dev": true
         },
         "pretty-ms": {
diff --git a/package.json b/package.json
index e5c13e7..3fa33af 100644
--- a/package.json
+++ b/package.json
@@ -29,9 +29,9 @@
     "homepage": "https://github.com/sveltejs/prettier-plugin-svelte#readme",
     "devDependencies": {
         "@types/node": "^10.12.18",
-        "@types/prettier": "^2.0.0",
+        "@types/prettier": "^2.0.2",
         "ava": "1.2.0",
-        "prettier": "^2.0.0",
+        "prettier": "^2.1.0",
         "rollup": "1.1.2",
         "rollup-plugin-commonjs": "9.2.0",
         "rollup-plugin-node-resolve": "4.0.0",
diff --git a/src/index.ts b/src/index.ts
index 4ae1980..cebe10a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,5 +1,6 @@
 import { SupportLanguage, Parser, Printer } from 'prettier';
 import { print } from './print';
+import { ASTNode } from './print/nodes';
 import { embed } from './embed';
 import { snipTagContent } from './lib/snipTagContent';
 
@@ -21,9 +22,9 @@ export const languages: Partial<SupportLanguage>[] = [
 
 export const parsers: Record<string, Parser> = {
     svelte: {
-        parse: text => {
+        parse: (text) => {
             try {
-                return require(`svelte/compiler`).parse(text);
+                return <ASTNode>{ ...require(`svelte/compiler`).parse(text), __isRoot: true };
             } catch (err) {
                 err.loc = {
                     start: err.start,
@@ -34,7 +35,7 @@ export const parsers: Record<string, Parser> = {
                 throw err;
             }
         },
-        preprocess: text => {
+        preprocess: (text) => {
             text = snipTagContent('style', text);
             text = snipTagContent('script', text, '{}');
             return text.trim();
diff --git a/src/lib/snipTagContent.ts b/src/lib/snipTagContent.ts
index dd819b7..fb62f02 100644
--- a/src/lib/snipTagContent.ts
+++ b/src/lib/snipTagContent.ts
@@ -1,5 +1,5 @@
 export function snipTagContent(tagName: string, source: string, placeholder = ''): string {
-    const regex = new RegExp(`[\s\n]*<${tagName}([^]*?)>([^]*?)<\/${tagName}>[\s\n]*`, 'gi');
+    const regex = new RegExp(`[\\s\n]*<${tagName}([^]*?)>([^]*?)<\/${tagName}>[\\s\n]*`, 'gi');
     return source.replace(regex, (_, attributes, content) => {
         const encodedContent = Buffer.from(content).toString('base64');
         return `<${tagName}${attributes} ✂prettier:content✂="${encodedContent}">${placeholder}</${tagName}>`;
diff --git a/src/print/helpers.ts b/src/print/helpers.ts
index 02e39b5..3007f92 100644
--- a/src/print/helpers.ts
+++ b/src/print/helpers.ts
@@ -1,19 +1,9 @@
-import { Node, ScriptNode, InstanceScriptNode, ModuleScriptNode } from './nodes';
-
-export interface ASTNode {
-    html: Node;
-    css?: Node & {
-        attributes: Node[];
-        children: Node[];
-        content: Node & {
-            styles: string;
-        };
-    };
-    js?: ScriptNode;
-    instance?: ScriptNode;
-    module?: ScriptNode;
-}
+import { ASTNode } from './nodes';
 
+/**
+ * Determines whether or not given node
+ * is the root of the Svelte AST.
+ */
 export function isASTNode(n: any): n is ASTNode {
-    return 'html' in n && 'tokens' in n;
+    return n && n.__isRoot;
 }
diff --git a/src/print/nodes.ts b/src/print/nodes.ts
index d8bcb64..dced6e7 100644
--- a/src/print/nodes.ts
+++ b/src/print/nodes.ts
@@ -285,3 +285,26 @@ export type Node =
     | ModuleScriptNode
     | BodyNode
     | OptionsNode;
+
+/**
+ * The Svelte AST root node
+ */
+export interface ASTNode {
+    html: Node;
+    css?: Node & {
+        attributes: Node[];
+        children: Node[];
+        content: Node & {
+            styles: string;
+        };
+    };
+    js?: ScriptNode;
+    instance?: ScriptNode;
+    module?: ScriptNode;
+    /**
+     * This is not actually part of the Svelte parser output,
+     * but we add it afterwards to make sure we can distinguish
+     * the root node from other nodes afterwards.
+     */
+    __isRoot: boolean;
+}


Test patch:
diff --git a/test/printer/samples/s-after-style-tag.html b/test/printer/samples/s-after-style-tag.html
new file mode 100644
index 0000000..ec56051
--- /dev/null
+++ b/test/printer/samples/s-after-style-tag.html
@@ -0,0 +1,5 @@
+<style>
+
+</style>
+
+sssssweet
diff --git a/test/printer/samples/script-inside-comment.html b/test/printer/samples/script-inside-comment.html
index a330bce..8af60b8 100644
--- a/test/printer/samples/script-inside-comment.html
+++ b/test/printer/samples/script-inside-comment.html
@@ -1,1 +1,1 @@
-<!-- <script>alert(1)</script> -->
+<!--<script>alert(1)</script>-->
diff --git a/test/printer/samples/style-inside-comment.html b/test/printer/samples/style-inside-comment.html
index 1fe9b58..8ba612f 100644
--- a/test/printer/samples/style-inside-comment.html
+++ b/test/printer/samples/style-inside-comment.html
@@ -1,1 +1,1 @@
-<!-- <style>div { color: red }</style> -->
+<!--<style>div { color: red }</style>-->