sveld 0.22.3 → 0.22.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/ComponentParser.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ interface ForwardedEvent {
|
|
|
29
29
|
name: string;
|
|
30
30
|
element: ComponentInlineElement | ComponentElement;
|
|
31
31
|
description?: string;
|
|
32
|
+
detail?: string;
|
|
32
33
|
}
|
|
33
34
|
interface DispatchedEvent {
|
|
34
35
|
type: "dispatched";
|
|
@@ -92,8 +93,8 @@ export default class ComponentParser {
|
|
|
92
93
|
private static assignValue;
|
|
93
94
|
private static formatComment;
|
|
94
95
|
/**
|
|
95
|
-
* Finds the last
|
|
96
|
-
*
|
|
96
|
+
* Finds the last comment from an array of leading comments.
|
|
97
|
+
* TypeScript directives are stripped before parsing, so we can safely take the last comment.
|
|
97
98
|
*/
|
|
98
99
|
private static findJSDocComment;
|
|
99
100
|
private sourceAtPos;
|
|
@@ -105,6 +106,10 @@ export default class ComponentParser {
|
|
|
105
106
|
private addDispatchedEvent;
|
|
106
107
|
private parseCustomTypes;
|
|
107
108
|
cleanup(): void;
|
|
109
|
+
/**
|
|
110
|
+
* Strips TypeScript directive comments from script blocks only.
|
|
111
|
+
*/
|
|
112
|
+
private static stripTypeScriptDirectivesFromScripts;
|
|
108
113
|
parseSvelteComponent(source: string, diagnostics: ComponentParserDiagnostics): ParsedComponent;
|
|
109
114
|
}
|
|
110
115
|
export {};
|
package/lib/ComponentParser.js
CHANGED
|
@@ -78,19 +78,13 @@ class ComponentParser {
|
|
|
78
78
|
return formatted_comment;
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
81
|
-
* Finds the last
|
|
82
|
-
*
|
|
81
|
+
* Finds the last comment from an array of leading comments.
|
|
82
|
+
* TypeScript directives are stripped before parsing, so we can safely take the last comment.
|
|
83
83
|
*/
|
|
84
84
|
static findJSDocComment(leadingComments) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
// JSDoc comments are block comments (/* */) where the value starts with *
|
|
89
|
-
if (comment.type === "Block" && comment.value.trimStart().startsWith("*")) {
|
|
90
|
-
return comment;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return undefined;
|
|
85
|
+
if (!leadingComments || leadingComments.length === 0)
|
|
86
|
+
return undefined;
|
|
87
|
+
return leadingComments[leadingComments.length - 1];
|
|
94
88
|
}
|
|
95
89
|
sourceAtPos(start, end) {
|
|
96
90
|
return this.source?.slice(start, end);
|
|
@@ -107,8 +101,6 @@ class ComponentParser {
|
|
|
107
101
|
return;
|
|
108
102
|
if (this.props.has(prop_name)) {
|
|
109
103
|
const existing_slot = this.props.get(prop_name);
|
|
110
|
-
if (!existing_slot)
|
|
111
|
-
return;
|
|
112
104
|
this.props.set(prop_name, {
|
|
113
105
|
...existing_slot,
|
|
114
106
|
...data,
|
|
@@ -123,8 +115,6 @@ class ComponentParser {
|
|
|
123
115
|
return;
|
|
124
116
|
if (this.moduleExports.has(prop_name)) {
|
|
125
117
|
const existing_slot = this.moduleExports.get(prop_name);
|
|
126
|
-
if (!existing_slot)
|
|
127
|
-
return;
|
|
128
118
|
this.moduleExports.set(prop_name, {
|
|
129
119
|
...existing_slot,
|
|
130
120
|
...data,
|
|
@@ -147,8 +137,6 @@ class ComponentParser {
|
|
|
147
137
|
const description = slot_description?.split("-").pop()?.trim();
|
|
148
138
|
if (this.slots.has(name)) {
|
|
149
139
|
const existing_slot = this.slots.get(name);
|
|
150
|
-
if (!existing_slot)
|
|
151
|
-
return;
|
|
152
140
|
this.slots.set(name, {
|
|
153
141
|
...existing_slot,
|
|
154
142
|
fallback,
|
|
@@ -262,14 +250,27 @@ class ComponentParser {
|
|
|
262
250
|
this.generics = null;
|
|
263
251
|
this.bindings.clear();
|
|
264
252
|
}
|
|
253
|
+
/**
|
|
254
|
+
* Strips TypeScript directive comments from script blocks only.
|
|
255
|
+
*/
|
|
256
|
+
static stripTypeScriptDirectivesFromScripts(source) {
|
|
257
|
+
// Find all script blocks and strip directives only from within them
|
|
258
|
+
return source.replace(/(<script[^>]*>)([\s\S]*?)(<\/script>)/gi, (_match, openTag, scriptContent, closeTag) => {
|
|
259
|
+
// Remove TypeScript directives from script content only
|
|
260
|
+
const cleanedContent = scriptContent.replace(/\/\/\s*@ts-[^\n\r]*/g, "");
|
|
261
|
+
return openTag + cleanedContent + closeTag;
|
|
262
|
+
});
|
|
263
|
+
}
|
|
265
264
|
parseSvelteComponent(source, diagnostics) {
|
|
266
265
|
if (this.options?.verbose) {
|
|
267
266
|
console.log(`[parsing] "${diagnostics.moduleName}" ${diagnostics.filePath}`);
|
|
268
267
|
}
|
|
269
268
|
this.cleanup();
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
this.
|
|
269
|
+
// Strip TypeScript directives from script blocks only to prevent interference with JSDoc
|
|
270
|
+
const cleanedSource = ComponentParser.stripTypeScriptDirectivesFromScripts(source);
|
|
271
|
+
this.source = cleanedSource;
|
|
272
|
+
this.compiled = (0, compiler_1.compile)(cleanedSource);
|
|
273
|
+
this.parsed = (0, compiler_1.parse)(cleanedSource);
|
|
273
274
|
this.collectReactiveVars();
|
|
274
275
|
this.parseCustomTypes();
|
|
275
276
|
if (this.parsed?.module) {
|
|
@@ -484,7 +485,7 @@ class ComponentParser {
|
|
|
484
485
|
replace: false,
|
|
485
486
|
};
|
|
486
487
|
if (value === undefined)
|
|
487
|
-
return
|
|
488
|
+
return {};
|
|
488
489
|
if (value[0]) {
|
|
489
490
|
const { type, expression, raw, start, end } = value[0];
|
|
490
491
|
if (type === "Text") {
|
|
@@ -554,8 +555,6 @@ class ComponentParser {
|
|
|
554
555
|
const element_name = parent.name;
|
|
555
556
|
if (this.bindings.has(prop_name)) {
|
|
556
557
|
const existing_bindings = this.bindings.get(prop_name);
|
|
557
|
-
if (!existing_bindings)
|
|
558
|
-
return;
|
|
559
558
|
if (!existing_bindings.elements.includes(element_name)) {
|
|
560
559
|
this.bindings.set(prop_name, {
|
|
561
560
|
...existing_bindings,
|
|
@@ -601,12 +600,18 @@ class ComponentParser {
|
|
|
601
600
|
if (event && event.type === "dispatched" && !actuallyDispatchedEvents.has(eventName)) {
|
|
602
601
|
const description = this.eventDescriptions.get(eventName);
|
|
603
602
|
const event_description = description?.split("-").pop()?.trim();
|
|
604
|
-
|
|
603
|
+
const forwardedEvent = {
|
|
605
604
|
type: "forwarded",
|
|
606
605
|
name: eventName,
|
|
607
606
|
element: element,
|
|
608
607
|
description: event_description,
|
|
609
|
-
}
|
|
608
|
+
};
|
|
609
|
+
// Only preserve detail if it was explicitly set and is not "null"
|
|
610
|
+
// (null means no detail was specified in @event tag)
|
|
611
|
+
if (event.detail !== undefined && event.detail !== "null") {
|
|
612
|
+
forwardedEvent.detail = event.detail;
|
|
613
|
+
}
|
|
614
|
+
this.events.set(eventName, forwardedEvent);
|
|
610
615
|
}
|
|
611
616
|
});
|
|
612
617
|
return {
|
|
@@ -634,9 +639,16 @@ class ComponentParser {
|
|
|
634
639
|
if (slot_props[key].replace && slot_props[key].value !== undefined) {
|
|
635
640
|
slot_props[key].value = this.props.get(slot_props[key].value)?.type;
|
|
636
641
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
642
|
+
let propValue = slot_props[key].value;
|
|
643
|
+
if (propValue === undefined) {
|
|
644
|
+
propValue = "any";
|
|
645
|
+
}
|
|
646
|
+
else if (typeof propValue === "string" && propValue.startsWith("{")) {
|
|
647
|
+
// If the value starts with {, it's a complex expression
|
|
648
|
+
// Use 'any' to avoid invalid TypeScript syntax
|
|
649
|
+
propValue = "any";
|
|
650
|
+
}
|
|
651
|
+
new_props.push(`${key}: ${propValue}`);
|
|
640
652
|
});
|
|
641
653
|
const formatted_slot_props = new_props.length === 0 ? "{}" : `{ ${new_props.join(", ")} }`;
|
|
642
654
|
return { ...slot, slot_props: formatted_slot_props };
|
|
@@ -176,7 +176,25 @@ function genEventDef(def) {
|
|
|
176
176
|
if (event.description) {
|
|
177
177
|
description = `/** ${event.description} */\n`;
|
|
178
178
|
}
|
|
179
|
-
|
|
179
|
+
let eventType;
|
|
180
|
+
if (event.type === "dispatched") {
|
|
181
|
+
eventType = createDispatchedEvent(event.detail);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
// For forwarded events, check if it's from a native HTML element or a component
|
|
185
|
+
// If element starts with uppercase, it's a component, so treat as CustomEvent
|
|
186
|
+
// Also check if the forwarded event has detail type information preserved
|
|
187
|
+
const elementName = typeof event.element === "string" ? event.element : event.element.name;
|
|
188
|
+
const isComponent = elementName && /^[A-Z]/.test(elementName);
|
|
189
|
+
const hasDetail = event.detail && event.detail !== "undefined" && event.detail !== "null";
|
|
190
|
+
if (isComponent || hasDetail) {
|
|
191
|
+
eventType = createDispatchedEvent(event.detail);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
eventType = `${mapEvent()}["${event.name}"]`;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return `${description}${clampKey(event.name)}: ${eventType};\n`;
|
|
180
198
|
})
|
|
181
199
|
.join("");
|
|
182
200
|
return `{${events_map}}`;
|