Skip to content

Commit 7bfe5a9

Browse files
authored
(fix) don't snip tag inside other tag (#220)
Fixes #219 Fixes the comment case of #70 Closes #72
1 parent 1adbc87 commit 7bfe5a9

File tree

4 files changed

+58
-11
lines changed

4 files changed

+58
-11
lines changed

src/index.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { SupportLanguage, Parser, Printer } from 'prettier';
22
import { print } from './print';
33
import { ASTNode } from './print/nodes';
44
import { embed } from './embed';
5-
import { snipTagContent } from './lib/snipTagContent';
5+
import { snipScriptAndStyleTagContent } from './lib/snipTagContent';
66

77
function locStart(node: any) {
88
return node.start;
@@ -40,8 +40,7 @@ export const parsers: Record<string, Parser> = {
4040
}
4141
},
4242
preprocess: (text, options) => {
43-
text = snipTagContent('style', text);
44-
text = snipTagContent('script', text, '{}');
43+
text = snipScriptAndStyleTagContent(text);
4544
text = text.trim();
4645
// Prettier sets the preprocessed text as the originalText in case
4746
// the Svelte formatter is called directly. In case it's called

src/lib/snipTagContent.ts

+48-8
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,54 @@
11
export const snippedTagContentAttribute = '✂prettier:content✂';
22

3-
export function snipTagContent(tagName: string, source: string, placeholder = ''): string {
4-
const regex = new RegExp(`<!--[^]*?-->|<${tagName}([^]*?)>([^]*?)<\/${tagName}>`, 'g');
5-
return source.replace(regex, (match, attributes, content) => {
6-
if (match.startsWith('<!--')) {
7-
return match;
3+
export function snipScriptAndStyleTagContent(source: string): string {
4+
const scriptMatchSpans = getMatchIndexes('script');
5+
const styleMatchSpans = getMatchIndexes('style');
6+
7+
return snipTagContent(
8+
snipTagContent(source, 'script', '{}', scriptMatchSpans, styleMatchSpans),
9+
'style',
10+
'',
11+
styleMatchSpans,
12+
scriptMatchSpans,
13+
);
14+
15+
function getMatchIndexes(tagName: string) {
16+
const regex = getRegexp(tagName);
17+
const indexes: [number, number][] = [];
18+
let match = null;
19+
while ((match = regex.exec(source)) != null) {
20+
indexes.push([match.index, regex.lastIndex]);
821
}
9-
const encodedContent = Buffer.from(content).toString('base64');
10-
return `<${tagName}${attributes} ${snippedTagContentAttribute}="${encodedContent}">${placeholder}</${tagName}>`;
11-
});
22+
return indexes;
23+
}
24+
25+
function snipTagContent(
26+
_source: string,
27+
tagName: string,
28+
placeholder: string,
29+
ownSpans: [number, number][],
30+
otherSpans: [number, number][],
31+
) {
32+
const regex = getRegexp(tagName);
33+
let idx = 0;
34+
return _source.replace(regex, (match, attributes, content) => {
35+
if (match.startsWith('<!--') || withinOtherSpan(idx)) {
36+
return match;
37+
}
38+
const encodedContent = Buffer.from(content).toString('base64');
39+
return `<${tagName}${attributes} ${snippedTagContentAttribute}="${encodedContent}">${placeholder}</${tagName}>`;
40+
});
41+
42+
function withinOtherSpan(idx: number) {
43+
return otherSpans.some(
44+
(otherSpan) => ownSpans[idx][0] > otherSpan[0] && ownSpans[idx][1] < otherSpan[1],
45+
);
46+
}
47+
}
48+
49+
function getRegexp(tagName: string) {
50+
return new RegExp(`<!--[^]*?-->|<${tagName}([^]*?)>([^]*?)<\/${tagName}>`, 'g');
51+
}
1252
}
1353

1454
export function hasSnippedContent(text: string) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<script>
2+
const str = "<style> .foo { color: blue; } </style>";
3+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
//<style>
3+
</script>
4+
5+
<style></style>

0 commit comments

Comments
 (0)