Skip to content

Commit e4c2194

Browse files
authored
(feat) support style directive (#1332)
Requires Svelte 3.46.1 or higher
1 parent a0b01ff commit e4c2194

File tree

12 files changed

+155
-32
lines changed

12 files changed

+155
-32
lines changed

packages/language-server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
"prettier": "2.5.1",
5656
"prettier-plugin-svelte": "~2.5.0",
5757
"source-map": "^0.7.3",
58-
"svelte": "^3.38.2",
58+
"svelte": "^3.46.1",
5959
"svelte-preprocess": "~4.10.1",
6060
"svelte2tsx": "~0.4.0",
6161
"typescript": "*",
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[
2+
{
3+
"range": {
4+
"start": { "line": 13, "character": 11 },
5+
"end": { "line": 13, "character": 16 }
6+
},
7+
"severity": 1,
8+
"source": "ts",
9+
"message": "Argument of type 'boolean' is not assignable to parameter of type 'String'.",
10+
"code": 2345,
11+
"tags": []
12+
},
13+
{
14+
"range": {
15+
"start": { "line": 14, "character": 18 },
16+
"end": { "line": 14, "character": 23 }
17+
},
18+
"severity": 1,
19+
"source": "ts",
20+
"message": "Argument of type 'boolean' is not assignable to parameter of type 'String'.",
21+
"code": 2345,
22+
"tags": []
23+
}
24+
]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script lang="ts">
2+
let right = 'string';
3+
let wrong = true;
4+
</script>
5+
6+
<!-- ok -->
7+
<div style:right />
8+
<div style:right={right} />
9+
<div style:right="right" />
10+
<div style:right={`right${right}`} />
11+
<div style:right=right{right} />
12+
13+
<!-- error -->
14+
<div style:wrong />
15+
<div style:wrong={wrong} />

packages/svelte2tsx/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"source-map": "^0.6.1",
3535
"source-map-support": "^0.5.16",
3636
"sourcemap-codec": "^1.4.8",
37-
"svelte": "~3.44.3",
37+
"svelte": "~3.46.1",
3838
"tiny-glob": "^0.2.6",
3939
"tslib": "^1.10.0",
4040
"typescript": "^4.5.3"

packages/svelte2tsx/src/htmlxtojsx/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import MagicString from 'magic-string';
22
import { walk } from 'svelte/compiler';
33
import { TemplateNode, Text } from 'svelte/types/compiler/interfaces';
4-
import { Attribute, BaseDirective, BaseNode } from '../interfaces';
4+
import { Attribute, BaseDirective, BaseNode, StyleDirective } from '../interfaces';
55
import { parseHtmlx } from '../utils/htmlxparser';
66
import { getSlotName } from '../utils/svelteAst';
77
import { handleActionDirective } from './nodes/action-directive';
@@ -21,6 +21,7 @@ import { IfScope } from './nodes/if-scope';
2121
import { handleKey } from './nodes/key';
2222
import { handleRawHtml } from './nodes/raw-html';
2323
import { handleSlot } from './nodes/slot';
24+
import { handleStyleDirective } from './nodes/style-directive';
2425
import { handleSvelteTag } from './nodes/svelte-tag';
2526
import { TemplateScopeManager } from './nodes/template-scope';
2627
import { handleText } from './nodes/text';
@@ -130,6 +131,9 @@ export function convertHtmlxToJsx(
130131
case 'Class':
131132
handleClassDirective(str, node as BaseDirective);
132133
break;
134+
case 'StyleDirective':
135+
handleStyleDirective(str, node as StyleDirective);
136+
break;
133137
case 'Action':
134138
handleActionDirective(htmlx, str, node as BaseDirective, parent);
135139
break;

packages/svelte2tsx/src/htmlxtojsx/nodes/attribute.ts

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import MagicString from 'magic-string';
22
import svgAttributes from '../svgattributes';
3-
import { isQuote } from '../utils/node-utils';
3+
import { buildTemplateString } from '../utils/node-utils';
44
import { Attribute, BaseNode } from '../../interfaces';
55

66
/**
@@ -109,6 +109,7 @@ export function handleAttribute(
109109
if (attr.value.length == 0) {
110110
return; //wut?
111111
}
112+
112113
//handle single value
113114
if (attr.value.length == 1) {
114115
const attrVal = attr.value[0];
@@ -203,29 +204,6 @@ export function handleAttribute(
203204
);
204205
}
205206

206-
function buildTemplateString(
207-
attr: Attribute,
208-
str: MagicString,
209-
htmlx: string,
210-
leadingOverride: string,
211-
trailingOverride: string
212-
) {
213-
const equals = htmlx.lastIndexOf('=', attr.value[0].start);
214-
str.overwrite(equals, attr.value[0].start, leadingOverride);
215-
216-
for (const n of attr.value as BaseNode[]) {
217-
if (n.type == 'MustacheTag') {
218-
str.appendRight(n.start, '$');
219-
}
220-
}
221-
222-
if (isQuote(htmlx[attr.end - 1])) {
223-
str.overwrite(attr.end - 1, attr.end, trailingOverride);
224-
} else {
225-
str.appendLeft(attr.end, trailingOverride);
226-
}
227-
}
228-
229207
function sanitizeLeadingChars(attrName: string): string {
230208
let sanitizedName = '';
231209
for (let i = 0; i < attrName.length; i++) {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import MagicString from 'magic-string';
2+
import { StyleDirective } from '../../interfaces';
3+
import { buildTemplateString } from '../utils/node-utils';
4+
5+
/**
6+
* style:xx ---> __sveltets_1_ensureType(String, xx);
7+
* style:xx={yy} ---> __sveltets_1_ensureType(String, yy);
8+
* style:xx="yy" ---> __sveltets_1_ensureType(String, "yy");
9+
* style:xx="a{b}" ---> __sveltets_1_ensureType(String, `a${b}`);
10+
*/
11+
export function handleStyleDirective(str: MagicString, style: StyleDirective): void {
12+
const htmlx = str.original;
13+
if (style.value === true || style.value.length === 0) {
14+
str.overwrite(
15+
style.start,
16+
htmlx.indexOf(':', style.start) + 1,
17+
'{...__sveltets_1_ensureType(String, '
18+
);
19+
str.appendLeft(style.end, ')}');
20+
return;
21+
}
22+
23+
if (style.value.length > 1) {
24+
buildTemplateString(
25+
style,
26+
str,
27+
htmlx,
28+
'{...__sveltets_1_ensureType(String, `',
29+
'`)}',
30+
style.start
31+
);
32+
return;
33+
}
34+
35+
const styleVal = style.value[0];
36+
if (styleVal.type === 'Text') {
37+
str.overwrite(style.start, styleVal.start, '{...__sveltets_1_ensureType(String, "');
38+
if (styleVal.end === style.end) {
39+
str.appendLeft(style.end, '")}');
40+
} else {
41+
str.overwrite(styleVal.end, style.end, '")}');
42+
}
43+
} else {
44+
// MustacheTag
45+
str.overwrite(style.start, styleVal.start + 1, '{...__sveltets_1_ensureType(String, ');
46+
str.overwrite(styleVal.end - 1, style.end, ')}');
47+
}
48+
}

packages/svelte2tsx/src/htmlxtojsx/utils/node-utils.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Node, walk } from 'estree-walker';
22
import MagicString from 'magic-string';
3-
import { BaseNode } from '../../interfaces';
3+
import { Attribute, BaseNode } from '../../interfaces';
44
import { surroundWithIgnoreComments } from '../../utils/ignore';
55

66
/**
@@ -249,3 +249,27 @@ export function getIdentifiersInIfExpression(
249249
export function usesLet(node: BaseNode): boolean {
250250
return node.attributes?.some((attr) => attr.type === 'Let');
251251
}
252+
253+
export function buildTemplateString(
254+
attr: Attribute,
255+
str: MagicString,
256+
htmlx: string,
257+
leadingOverride: string,
258+
trailingOverride: string,
259+
overrideStart?: number
260+
) {
261+
overrideStart = overrideStart ?? htmlx.lastIndexOf('=', attr.value[0].start);
262+
str.overwrite(overrideStart, attr.value[0].start, leadingOverride);
263+
264+
for (const n of attr.value as BaseNode[]) {
265+
if (n.type == 'MustacheTag') {
266+
str.appendRight(n.start, '$');
267+
}
268+
}
269+
270+
if (isQuote(htmlx[attr.end - 1])) {
271+
str.overwrite(attr.end - 1, attr.end, trailingOverride);
272+
} else {
273+
str.appendLeft(attr.end, trailingOverride);
274+
}
275+
}

packages/svelte2tsx/src/interfaces.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,7 @@ export interface BaseDirective extends BaseNode {
3636
export interface Attribute extends BaseNode {
3737
value: BaseNode[] | true;
3838
}
39+
40+
export interface StyleDirective extends BaseNode {
41+
value: BaseNode[] | true;
42+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<><div {...__sveltets_1_ensureType(String, shorthand)}>Hello</div>
2+
<div {...__sveltets_1_ensureType(String, value)}>Hello</div>
3+
<div {...__sveltets_1_ensureType(String, value)}>Hello</div>
4+
<div {...__sveltets_1_ensureType(String, value)}>Hello</div>
5+
<div {...__sveltets_1_ensureType(String, "string")}>Hello</div>
6+
<div {...__sveltets_1_ensureType(String, "string")}>Hello</div>
7+
<div {...__sveltets_1_ensureType(String, `string${mixed}`)}>Hello</div>
8+
<div {...__sveltets_1_ensureType(String, `string${mixed}`)}>Hello</div>
9+
<div {...__sveltets_1_ensureType(String, `${mixed}string`)}>Hello</div>
10+
<div {...__sveltets_1_ensureType(String, `string${mixed}string`)}>Hello</div>
11+
<div {...__sveltets_1_ensureType(String, `template${literal}`)}>Hello</div>
12+
13+
<div {...__sveltets_1_ensureType(String, shorthand)} /></>

0 commit comments

Comments
 (0)