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

Issue:
Cannot nest `<style>..</style>` inside script tag
Hey all, 

Here's a bizarre random behavior with an incredibly small reproduction.

When creating this file:
```typescript
<script lang="ts">
  const test = '<style>.cls-1{fill:#231f20;}.cls-2{fill:#b06010;}.cls-3{fill:#578bac;}.cls-4{fill:#00446a;}.cls-5{fill:#afb1b4;}.cls-6{fill:#696a6d;}.cls-7{fill:#d7a374;}.cls-8{fill:#c1c17d;}.cls-9{fill:#8a8d09;}</style>'
</script>
```

If I format it:
```typescript
<script lang="ts">
	const test =
		'<style ✂prettier:content✂="LmNscy0xe2ZpbGw6IzIzMWYyMDt9LmNscy0ye2ZpbGw6I2IwNjAxMDt9LmNscy0ze2ZpbGw6IzU3OGJhYzt9LmNscy00e2ZpbGw6IzAwNDQ2YTt9LmNscy01e2ZpbGw6I2FmYjFiNDt9LmNscy02e2ZpbGw6IzY5NmE2ZDt9LmNscy03e2ZpbGw6I2Q3YTM3NDt9LmNscy04e2ZpbGw6I2MxYzE3ZDt9LmNscy05e2ZpbGw6IzhhOGQwOTt9"></style>';
</script>
```

That's... weird.

Here's my .prettierrc:
```json
{
	"useTabs": true,
	"singleQuote": true,
	"trailingComma": "es5",
	"printWidth": 120
}

```

Pull request:
(fix) don't snip tag inside other tag
Fixes #219
Fixes the comment case of #70 
Closes #72

Patch:
diff --git a/src/index.ts b/src/index.ts
index d1b11f6..af3c060 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -2,7 +2,7 @@ import { SupportLanguage, Parser, Printer } from 'prettier';
 import { print } from './print';
 import { ASTNode } from './print/nodes';
 import { embed } from './embed';
-import { snipTagContent } from './lib/snipTagContent';
+import { snipScriptAndStyleTagContent } from './lib/snipTagContent';
 
 function locStart(node: any) {
     return node.start;
@@ -40,8 +40,7 @@ export const parsers: Record<string, Parser> = {
             }
         },
         preprocess: (text, options) => {
-            text = snipTagContent('style', text);
-            text = snipTagContent('script', text, '{}');
+            text = snipScriptAndStyleTagContent(text);
             text = text.trim();
             // Prettier sets the preprocessed text as the originalText in case
             // the Svelte formatter is called directly. In case it's called
diff --git a/src/lib/snipTagContent.ts b/src/lib/snipTagContent.ts
index b61757a..e3557f5 100644
--- a/src/lib/snipTagContent.ts
+++ b/src/lib/snipTagContent.ts
@@ -1,14 +1,54 @@
 export const snippedTagContentAttribute = '✂prettier:content✂';
 
-export function snipTagContent(tagName: string, source: string, placeholder = ''): string {
-    const regex = new RegExp(`<!--[^]*?-->|<${tagName}([^]*?)>([^]*?)<\/${tagName}>`, 'g');
-    return source.replace(regex, (match, attributes, content) => {
-        if (match.startsWith('<!--')) {
-            return match;
+export function snipScriptAndStyleTagContent(source: string): string {
+    const scriptMatchSpans = getMatchIndexes('script');
+    const styleMatchSpans = getMatchIndexes('style');
+
+    return snipTagContent(
+        snipTagContent(source, 'script', '{}', scriptMatchSpans, styleMatchSpans),
+        'style',
+        '',
+        styleMatchSpans,
+        scriptMatchSpans,
+    );
+
+    function getMatchIndexes(tagName: string) {
+        const regex = getRegexp(tagName);
+        const indexes: [number, number][] = [];
+        let match = null;
+        while ((match = regex.exec(source)) != null) {
+            indexes.push([match.index, regex.lastIndex]);
         }
-        const encodedContent = Buffer.from(content).toString('base64');
-        return `<${tagName}${attributes} ${snippedTagContentAttribute}="${encodedContent}">${placeholder}</${tagName}>`;
-    });
+        return indexes;
+    }
+
+    function snipTagContent(
+        _source: string,
+        tagName: string,
+        placeholder: string,
+        ownSpans: [number, number][],
+        otherSpans: [number, number][],
+    ) {
+        const regex = getRegexp(tagName);
+        let idx = 0;
+        return _source.replace(regex, (match, attributes, content) => {
+            if (match.startsWith('<!--') || withinOtherSpan(idx)) {
+                return match;
+            }
+            const encodedContent = Buffer.from(content).toString('base64');
+            return `<${tagName}${attributes} ${snippedTagContentAttribute}="${encodedContent}">${placeholder}</${tagName}>`;
+        });
+
+        function withinOtherSpan(idx: number) {
+            return otherSpans.some(
+                (otherSpan) => ownSpans[idx][0] > otherSpan[0] && ownSpans[idx][1] < otherSpan[1],
+            );
+        }
+    }
+
+    function getRegexp(tagName: string) {
+        return new RegExp(`<!--[^]*?-->|<${tagName}([^]*?)>([^]*?)<\/${tagName}>`, 'g');
+    }
 }
 
 export function hasSnippedContent(text: string) {


Test patch:
diff --git a/test/printer/samples/style-inside-script.html b/test/printer/samples/style-inside-script.html
new file mode 100644
index 0000000..d12761e
--- /dev/null
+++ b/test/printer/samples/style-inside-script.html
@@ -0,0 +1,3 @@
+<script>
+    const str = "<style> .foo { color: blue; } </style>";
+</script>
diff --git a/test/printer/samples/style-unclosed-inside-script.html b/test/printer/samples/style-unclosed-inside-script.html
new file mode 100644
index 0000000..3f1fbec
--- /dev/null
+++ b/test/printer/samples/style-unclosed-inside-script.html
@@ -0,0 +1,5 @@
+<script>
+    //<style>
+</script>
+
+<style></style>