Skip to content

Commit 497cd3f

Browse files
committed
feat!: change AST of an attribute value
1 parent 48f7e5e commit 497cd3f

File tree

215 files changed

+13096
-13610
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

215 files changed

+13096
-13610
lines changed

docs/AST.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,19 @@ interface SvelteAttribute extends Node {
210210
type: "SvelteAttribute";
211211
key: SvelteName;
212212
boolean: boolean;
213-
value: (SvelteLiteral | SvelteMustacheTagText)[];
213+
value: SvelteLiteral | SvelteMustacheTagText | SvelteAttributeTemplateValue | null;
214+
}
215+
```
216+
217+
### SvelteAttributeTemplateValue
218+
219+
If the value of the attribute becomes a template, this node is set to the `value`.
220+
221+
```ts
222+
interface SvelteAttributeTemplateValue extends Node {
223+
type: "SvelteAttributeTemplateValue";
224+
values: (SvelteLiteral | SvelteMustacheTagText)[];
225+
parent: SvelteAttribute | SvelteStyleDirective;
214226
}
215227
```
216228

@@ -321,7 +333,7 @@ interface SvelteStyleDirective extends Node {
321333
type: "SvelteStyleDirective";
322334
key: SvelteDirectiveKey;
323335
shorthand: boolean;
324-
value: (SvelteLiteral | SvelteMustacheTagText)[];
336+
value: SvelteLiteral | SvelteMustacheTagText | SvelteAttributeTemplateValue | null;
325337
}
326338
```
327339

src/ast/html.ts

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export type SvelteHTMLNode =
2525
| SvelteAwaitCatchBlock
2626
| SvelteKeyBlock
2727
| SvelteAttribute
28+
| SvelteAttributeTemplateValue
2829
| SvelteShorthandAttribute
2930
| SvelteSpreadAttribute
3031
| SvelteDirective
@@ -200,7 +201,7 @@ export interface SvelteText extends BaseNode {
200201
export interface SvelteLiteral extends BaseNode {
201202
type: "SvelteLiteral";
202203
value: string;
203-
parent: SvelteAttribute | SvelteStyleDirective;
204+
parent: SvelteAttribute | SvelteStyleDirective | SvelteAttributeTemplateValue;
204205
}
205206

206207
/** Node of mustache tag. e.g. `{...}`, `{@html ...}`. Like JSXExpressionContainer */
@@ -220,6 +221,7 @@ interface BaseSvelteMustacheTag extends BaseNode {
220221
| SvelteAwaitCatchBlock
221222
| SvelteKeyBlock
222223
| SvelteAttribute
224+
| SvelteAttributeTemplateValue
223225
| SvelteStyleDirective;
224226
}
225227
/** Node of mustache tag. e.g. `{...}``. Like JSXExpressionContainer */
@@ -460,13 +462,31 @@ export interface SvelteHTMLComment extends BaseNode {
460462
| SvelteKeyBlock;
461463
}
462464
/** Node of HTML attribute. */
463-
export interface SvelteAttribute extends BaseNode {
465+
export type SvelteAttribute = SvelteAttributeBoolean | SvelteAttributeWithValue;
466+
interface BaseSvelteAttribute extends BaseNode {
464467
type: "SvelteAttribute";
465468
key: SvelteName;
466469
boolean: boolean;
467-
value: (SvelteLiteral | SvelteMustacheTagText)[];
470+
value:
471+
| SvelteLiteral
472+
| SvelteMustacheTagText
473+
| SvelteAttributeTemplateValue
474+
| null;
468475
parent: SvelteStartTag;
469476
}
477+
export interface SvelteAttributeBoolean extends BaseSvelteAttribute {
478+
boolean: true;
479+
value: null;
480+
}
481+
export interface SvelteAttributeWithValue extends BaseSvelteAttribute {
482+
boolean: false;
483+
value: SvelteLiteral | SvelteMustacheTagText | SvelteAttributeTemplateValue;
484+
}
485+
export interface SvelteAttributeTemplateValue extends BaseNode {
486+
type: "SvelteAttributeTemplateValue";
487+
values: (SvelteLiteral | SvelteMustacheTagText)[];
488+
parent: SvelteAttributeWithValue | SvelteStyleDirectiveLongform;
489+
}
470490
/** Node of shorthand attribute. e.g. `<img {src}>` */
471491
export interface SvelteShorthandAttribute extends BaseNode {
472492
type: "SvelteShorthandAttribute";
@@ -574,19 +594,23 @@ export type SvelteStyleDirective =
574594
interface BaseSvelteStyleDirective extends BaseNode {
575595
type: "SvelteStyleDirective";
576596
key: SvelteDirectiveKeyTextName | SvelteDirectiveKeyForStyleShorthand;
577-
value: (SvelteLiteral | SvelteMustacheTagText)[];
597+
value:
598+
| SvelteLiteral
599+
| SvelteMustacheTagText
600+
| SvelteAttributeTemplateValue
601+
| null;
578602
parent: SvelteStartTag;
579603
}
580604
export interface SvelteStyleDirectiveShorthand
581605
extends BaseSvelteStyleDirective {
582606
key: SvelteDirectiveKeyForStyleShorthand;
583607
shorthand: true;
584-
value: [];
608+
value: null;
585609
}
586610
export interface SvelteStyleDirectiveLongform extends BaseSvelteStyleDirective {
587611
key: SvelteDirectiveKeyTextName;
588612
shorthand: false;
589-
value: (SvelteLiteral | SvelteMustacheTagText)[];
613+
value: SvelteLiteral | SvelteMustacheTagText | SvelteAttributeTemplateValue;
590614
}
591615
export interface SvelteSpecialDirectiveKey extends BaseNode {
592616
type: "SvelteSpecialDirectiveKey";

src/parser/converts/attr.ts

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ import type {
2020
SvelteStyleElement,
2121
SvelteElseBlock,
2222
SvelteAwaitBlock,
23+
SvelteLiteral,
24+
SvelteMustacheTagText,
25+
SvelteAttributeWithValue,
2326
} from "../../ast";
2427
import type ESTree from "estree";
2528
import type { Context } from "../../context";
@@ -114,9 +117,9 @@ export function* convertAttributeTokens(
114117
for (const attr of attributes) {
115118
const attribute: SvelteAttribute = {
116119
type: "SvelteAttribute",
117-
boolean: false,
120+
boolean: false as boolean,
118121
key: null as any,
119-
value: [],
122+
value: null as any,
120123
parent,
121124
...ctx.getConvertLocation({
122125
start: attr.key.start,
@@ -133,8 +136,10 @@ export function* convertAttributeTokens(
133136
if (attr.value == null) {
134137
attribute.boolean = true;
135138
} else {
136-
attribute.value.push(
137-
convertAttributeValueTokenToLiteral(attr.value, attribute, ctx),
139+
attribute.value = convertAttributeValueTokenToLiteral(
140+
attr.value,
141+
attribute,
142+
ctx,
138143
);
139144
}
140145
yield attribute;
@@ -149,9 +154,9 @@ function convertAttribute(
149154
): SvelteAttribute | SvelteShorthandAttribute {
150155
const attribute: SvelteAttribute = {
151156
type: "SvelteAttribute",
152-
boolean: false,
157+
boolean: false as boolean,
153158
key: null as any,
154-
value: [],
159+
value: null as any,
155160
parent,
156161
...ctx.getConvertLocation(node),
157162
};
@@ -215,6 +220,7 @@ function processAttributeValue(
215220
attribute: SvelteAttribute | SvelteStyleDirectiveLongform,
216221
ctx: Context,
217222
) {
223+
const values: (SvelteLiteral | SvelteMustacheTagText)[] = [];
218224
for (let index = 0; index < nodeValue.length; index++) {
219225
const v = nodeValue[index];
220226
if (v.type === "Text") {
@@ -229,12 +235,12 @@ function processAttributeValue(
229235
// console.log(ctx.getText(v), v.data)
230236
v.end = next.start;
231237
}
232-
attribute.value.push(convertTextToLiteral(v, attribute, ctx));
238+
values.push(convertTextToLiteral(v, attribute, ctx));
233239
continue;
234240
}
235241
if (v.type === "MustacheTag") {
236242
const mustache = convertMustacheTag(v, attribute, ctx);
237-
attribute.value.push(mustache);
243+
values.push(mustache);
238244
continue;
239245
}
240246
const u: any = v;
@@ -244,6 +250,29 @@ function processAttributeValue(
244250
ctx,
245251
);
246252
}
253+
if (values.length === 1) {
254+
attribute.value = values[0];
255+
} else if (values.length === 0) {
256+
attribute.value = null;
257+
} else {
258+
const first = values[0];
259+
const last = values[values.length - 1];
260+
attribute.value = {
261+
type: "SvelteAttributeTemplateValue",
262+
values,
263+
parent: attribute as
264+
| SvelteAttributeWithValue
265+
| SvelteStyleDirectiveLongform,
266+
loc: {
267+
start: { ...first.loc.start },
268+
end: { ...last.loc.end },
269+
},
270+
range: [first.range[0], last.range[1]],
271+
};
272+
for (const value of values) {
273+
value.parent = attribute.value;
274+
}
275+
}
247276
}
248277

249278
/** Convert for Spread */
@@ -458,7 +487,7 @@ function convertStyleDirective(
458487
type: "SvelteStyleDirective",
459488
key: null as any,
460489
shorthand: false,
461-
value: [],
490+
value: null as any,
462491
parent,
463492
...ctx.getConvertLocation(node),
464493
};

src/parser/converts/element.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ function processThisAttribute(
476476
type: "SvelteAttribute",
477477
key: null as any,
478478
boolean: false,
479-
value: [],
479+
value: null as any,
480480
parent: element.startTag,
481481
...ctx.getConvertLocation({ start: startIndex, end: endIndex }),
482482
};
@@ -486,15 +486,15 @@ function processThisAttribute(
486486
parent: thisAttr,
487487
...ctx.getConvertLocation({ start: startIndex, end: eqIndex }),
488488
};
489-
thisAttr.value.push({
489+
thisAttr.value = {
490490
type: "SvelteLiteral",
491491
value: thisValue,
492492
parent: thisAttr,
493493
...ctx.getConvertLocation({
494494
start: literalStartIndex,
495495
end: literalEndIndex,
496496
}),
497-
});
497+
};
498498
// this
499499
ctx.addToken("HTMLIdentifier", {
500500
start: startIndex,

src/parser/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,9 @@ function parseAsSvelte(
166166
(attr) =>
167167
attr.type === "SvelteAttribute" &&
168168
attr.key.name === "context" &&
169-
attr.value.length === 1 &&
170-
attr.value[0].type === "SvelteLiteral" &&
171-
attr.value[0].value === "module",
169+
attr.value &&
170+
attr.value.type === "SvelteLiteral" &&
171+
attr.value.value === "module",
172172
)
173173
) {
174174
analyzePropsScope(body, resultScript.scopeManager!);

src/parser/style-context.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ export function parseStyleContext(
4747
if (
4848
attribute.type === "SvelteAttribute" &&
4949
attribute.key.name === "lang" &&
50-
attribute.value.length > 0 &&
51-
attribute.value[0].type === "SvelteLiteral"
50+
attribute.value &&
51+
attribute.value.type === "SvelteLiteral"
5252
) {
53-
sourceLang = attribute.value[0].value;
53+
sourceLang = attribute.value.value;
5454
}
5555
}
5656
let parseFn: Parser<Root>, sourceAst: Root;

src/parser/typescript/analyze/index.ts

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -204,33 +204,7 @@ function analyzeDollarDollarVariables(
204204
case "$$slots": {
205205
const nameTypes = new Set<string>();
206206
for (const slot of slots) {
207-
const nameAttr = slot.startTag.attributes.find(
208-
(attr): attr is SvelteAttribute =>
209-
attr.type === "SvelteAttribute" && attr.key.name === "name",
210-
);
211-
if (!nameAttr || nameAttr.value.length === 0) {
212-
nameTypes.add('"default"');
213-
continue;
214-
}
215-
216-
if (nameAttr.value.length === 1) {
217-
const value = nameAttr.value[0];
218-
if (value.type === "SvelteLiteral") {
219-
nameTypes.add(JSON.stringify(value.value));
220-
} else {
221-
nameTypes.add("string");
222-
}
223-
continue;
224-
}
225-
nameTypes.add(
226-
`\`${nameAttr.value
227-
.map((value) =>
228-
value.type === "SvelteLiteral"
229-
? value.value.replace(/([$`])/gu, "\\$1")
230-
: "${string}",
231-
)
232-
.join("")}\``,
233-
);
207+
nameTypes.add(extractSlotTypes(slot));
234208
}
235209

236210
appendDeclareVirtualScript(
@@ -254,6 +228,34 @@ function analyzeDollarDollarVariables(
254228
}
255229
}
256230

231+
/** Extract slot name type from given the slot element */
232+
function extractSlotTypes(slot: SvelteHTMLElement) {
233+
const nameAttr = slot.startTag.attributes.find(
234+
(attr): attr is SvelteAttribute =>
235+
attr.type === "SvelteAttribute" && attr.key.name === "name",
236+
);
237+
if (!nameAttr || nameAttr.boolean || nameAttr.value == null) {
238+
return '"default"';
239+
}
240+
241+
if (nameAttr.value.type === "SvelteLiteral") {
242+
return JSON.stringify(nameAttr.value.value);
243+
}
244+
if (nameAttr.value.type === "SvelteMustacheTag") {
245+
return "string";
246+
}
247+
if (nameAttr.value.type === "SvelteAttributeTemplateValue") {
248+
return `\`${nameAttr.value.values
249+
.map((value) =>
250+
value.type === "SvelteLiteral"
251+
? value.value.replace(/([$`])/gu, "\\$1")
252+
: "${string}",
253+
)
254+
.join("")}\``;
255+
}
256+
throw Error(`Unknown attr value type: ${(nameAttr.value as any).type}`);
257+
}
258+
257259
/** Append declare virtual script */
258260
function appendDeclareVirtualScript(name: string, type: string) {
259261
ctx.appendVirtualScript(`declare let ${name}: ${type};`);

src/visitor-keys.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ const svelteKeys: SvelteKeysType = {
3838
SvelteAwaitCatchBlock: ["error", "children"],
3939
SvelteKeyBlock: ["expression", "children"],
4040
SvelteAttribute: ["key", "value"],
41+
SvelteAttributeTemplateValue: ["values"],
4142
SvelteShorthandAttribute: ["key", "value"],
4243
SvelteSpreadAttribute: ["argument"],
4344
SvelteDirective: ["key", "expression"],

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy