@wc-toolkit/svelte-types 1.0.0

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/dist/index.js ADDED
@@ -0,0 +1,797 @@
1
+ // src/type-generator.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import prettier from "@prettier/sync";
5
+
6
+ // node_modules/.pnpm/@wc-toolkit+cem-utilities@1.4.1/node_modules/@wc-toolkit/cem-utilities/dist/index.js
7
+ var JS_TYPES = /* @__PURE__ */ new Set([
8
+ "any",
9
+ "bigint",
10
+ "boolean",
11
+ "never",
12
+ "null",
13
+ "number",
14
+ "string",
15
+ "Symbol",
16
+ "undefined",
17
+ "unknown"
18
+ ]);
19
+ var DOM_EVENTS = /* @__PURE__ */ new Set([
20
+ "AnimationEvent",
21
+ "BeforeUnloadEvent",
22
+ "ClipboardEvent",
23
+ "DragEvent",
24
+ "Event",
25
+ "FocusEvent",
26
+ "HashChangeEvent",
27
+ "InputEvent",
28
+ "KeyboardEvent",
29
+ "MessageEvent",
30
+ "MouseEvent",
31
+ "MutationObserver",
32
+ "PageTransitionEvent",
33
+ "PointerEvent",
34
+ "PopStateEvent",
35
+ "ProgressEvent",
36
+ "StorageEvent",
37
+ "TouchEvent",
38
+ "TransitionEvent",
39
+ "UIEvent",
40
+ "WebGLContextEvent",
41
+ "WheelEvent"
42
+ ]);
43
+ var definitionExports = /* @__PURE__ */ new Map();
44
+ var components = [];
45
+ var manifest;
46
+ function getAllComponents(customElementsManifest, exclude = []) {
47
+ if (!customElementsManifest) {
48
+ return [];
49
+ }
50
+ if (!customElementsManifest || areObjectsEqual(customElementsManifest, manifest)) {
51
+ return components;
52
+ }
53
+ resetCache();
54
+ manifest = customElementsManifest;
55
+ setAllDefinitionExports(customElementsManifest);
56
+ manifest.modules.forEach((module) => {
57
+ const ces = module.declarations?.filter(
58
+ (d) => d.customElement
59
+ );
60
+ if (ces?.length) {
61
+ ces.forEach((ce) => {
62
+ if (exclude?.includes(ce.name)) {
63
+ return;
64
+ }
65
+ ce.modulePath = module.path;
66
+ ce.definitionPath = definitionExports.get(ce.name);
67
+ if ("typeDefinitionPath" in module && module.typeDefinitionPath) {
68
+ ce.typeDefinitionPath = module.typeDefinitionPath;
69
+ }
70
+ components.push(ce);
71
+ });
72
+ }
73
+ });
74
+ return components;
75
+ }
76
+ function resetCache() {
77
+ components = [];
78
+ manifest = void 0;
79
+ definitionExports.clear();
80
+ }
81
+ function getComponentPublicProperties(component) {
82
+ if (!component || !component.members) {
83
+ return [];
84
+ }
85
+ return component?.members?.filter(
86
+ (member) => member.kind === "field" && member.privacy !== "private" && member.privacy !== "protected" && !member.static && !member.name.startsWith("#")
87
+ ) || [];
88
+ }
89
+ function getComponentPublicMethods(component) {
90
+ if (!component || !component.members) {
91
+ return [];
92
+ }
93
+ const getParameter = (p) => p.name + getParamType(p) + getParamDefaultValue(p);
94
+ const getParamType = (p) => p.type?.text ? `${p.optional ? "?" : ""}: ${p.type?.text}` : "";
95
+ const getParamDefaultValue = (p) => p.default ? ` = ${p.default}` : "";
96
+ return (
97
+ // filter to return only public methods
98
+ component?.members?.filter(
99
+ (member) => member.kind === "method" && member.privacy !== "private" && member.privacy !== "protected" && !member.name.startsWith("#")
100
+ )?.map((m) => {
101
+ m.type = {
102
+ text: `${m.name}(${m.parameters?.map((p) => getParameter(p)).join(", ") || ""}) => ${m.return?.type?.text || "void"}`
103
+ };
104
+ return m;
105
+ })
106
+ );
107
+ }
108
+ function getCustomEventDetailTypes(component, excludedTypes) {
109
+ if (!component || !component.events) {
110
+ return [];
111
+ }
112
+ const types = component?.events?.map((e) => {
113
+ const eventType = e.type?.text.replace("[]", "").replace(" | undefined", "");
114
+ return eventType && !excludedTypes?.includes(eventType) && !JS_TYPES.has(eventType) && !DOM_EVENTS.has(eventType) && !eventType.includes("<") && !eventType.includes(">") && !eventType.includes(`{`) && !eventType.includes("'") && !eventType.includes(`"`) ? eventType : void 0;
115
+ })?.filter((e) => e !== void 0 && !e?.startsWith("HTML")) || [];
116
+ return types?.length ? [...new Set(types)] : [];
117
+ }
118
+ function setAllDefinitionExports(customElementsManifest) {
119
+ if (!customElementsManifest) {
120
+ return;
121
+ }
122
+ customElementsManifest.modules.forEach((mod) => {
123
+ const defExports = mod?.exports?.filter(
124
+ (e) => e.kind === "custom-element-definition"
125
+ );
126
+ if (defExports?.length) {
127
+ defExports.forEach((e) => {
128
+ if (e.declaration.name) {
129
+ definitionExports.set(e.declaration.name, mod.path);
130
+ }
131
+ });
132
+ }
133
+ });
134
+ }
135
+ function areObjectsEqual(obj1, obj2) {
136
+ if (obj1 === obj2) return true;
137
+ if (obj1 === null || obj2 === null || typeof obj1 !== "object" || typeof obj2 !== "object")
138
+ return false;
139
+ if (Array.isArray(obj1) && Array.isArray(obj2)) {
140
+ if (obj1.length !== obj2.length) return false;
141
+ return obj1.every((item, index) => areObjectsEqual(item, obj2[index]));
142
+ }
143
+ const keys1 = Object.keys(obj1);
144
+ const keys2 = Object.keys(obj2);
145
+ if (keys1.length !== keys2.length) return false;
146
+ if (!keys2.every((key) => key in obj1)) return false;
147
+ return keys1.every((key) => {
148
+ const val1 = obj1[key];
149
+ const val2 = obj2[key];
150
+ if (val1 === null && val2 === null) return true;
151
+ if (val1 === null || val2 === null) return false;
152
+ if (typeof val1 === "object" && typeof val2 === "object") {
153
+ return areObjectsEqual(val1, val2);
154
+ }
155
+ return val1 === val2;
156
+ });
157
+ }
158
+ function deepMerge(target, source) {
159
+ if (typeof target !== "object" || target === null) {
160
+ return source;
161
+ }
162
+ if (typeof source !== "object" || source === null) {
163
+ return target;
164
+ }
165
+ const targetObj = target;
166
+ const sourceObj = source;
167
+ for (const key of Object.keys(source)) {
168
+ if (sourceObj[key] instanceof Array) {
169
+ if (!targetObj[key]) {
170
+ targetObj[key] = [];
171
+ }
172
+ targetObj[key] = targetObj[key].concat(sourceObj[key]);
173
+ } else if (sourceObj[key] instanceof Object) {
174
+ if (!targetObj[key]) {
175
+ targetObj[key] = {};
176
+ }
177
+ targetObj[key] = deepMerge(targetObj[key], sourceObj[key]);
178
+ } else {
179
+ targetObj[key] = sourceObj[key];
180
+ }
181
+ }
182
+ return targetObj;
183
+ }
184
+ function getComponentDetailsTemplate(component, options, isJsDoc) {
185
+ if (!component) {
186
+ throw new Error("Component is required");
187
+ }
188
+ const apiOptions = deepMerge(
189
+ defaultDescriptionOptions,
190
+ options
191
+ );
192
+ let description = getMainComponentDescription(
193
+ component,
194
+ apiOptions.descriptionSrc
195
+ );
196
+ const headingLevel = createMarkdownHeading(
197
+ apiOptions.sectionHeadingLevel || 2
198
+ );
199
+ apiOptions.order?.forEach((key) => {
200
+ const componentContent = getApiByOrderOption(component, key);
201
+ const api = apiOptions.apis ? apiOptions.apis[key] : void 0;
202
+ if (api && componentContent?.length) {
203
+ description += `
204
+
205
+ ${headingLevel} ${api.heading}`;
206
+ description += api.description ? `
207
+
208
+ ${api.description}` : "";
209
+ description += api.template ? (
210
+ // @ts-expect-error componentContent takes many shapes
211
+ `
212
+
213
+ ${api.template(componentContent)}`
214
+ ) : "";
215
+ }
216
+ });
217
+ if (isJsDoc) {
218
+ description = description.split("\n").map((x) => ` * ${x}`).join("\n");
219
+ }
220
+ return description;
221
+ }
222
+ function getApiByOrderOption(component, api) {
223
+ if (!component || !api) {
224
+ return [];
225
+ }
226
+ switch (api) {
227
+ case "attributes":
228
+ return component.attributes || [];
229
+ case "properties":
230
+ return getComponentPublicProperties(component) || [];
231
+ case "attrsAndProps": {
232
+ return getAttrsAndProps(component);
233
+ }
234
+ case "propsOnly": {
235
+ return getPropertyOnlyFields(component);
236
+ }
237
+ case "events":
238
+ return component.events || [];
239
+ case "methods":
240
+ return getComponentPublicMethods(component);
241
+ case "slots":
242
+ return component.slots || [];
243
+ case "cssProps":
244
+ return component.cssProperties || [];
245
+ case "cssParts":
246
+ return component.cssParts || [];
247
+ case "cssState":
248
+ return component.cssStates || [];
249
+ default:
250
+ return [];
251
+ }
252
+ }
253
+ function getMainComponentDescription(component, descriptionSrc) {
254
+ if (!component) {
255
+ return "";
256
+ }
257
+ let description = (descriptionSrc ? component[descriptionSrc] : component.summary || component.description)?.replace(/\\n/g, "\n") || "";
258
+ if (component.deprecated) {
259
+ const deprecation = typeof component.deprecated === "string" ? `@deprecated ${component.deprecated}` : "@deprecated";
260
+ description = `${deprecation}
261
+
262
+ ${description}`;
263
+ }
264
+ return description;
265
+ }
266
+ function getAttrsAndProps(component) {
267
+ if (!component) {
268
+ return [];
269
+ }
270
+ const attributes = component.attributes?.map((attr) => {
271
+ return {
272
+ attrName: attr.name,
273
+ propName: attr.fieldName,
274
+ summary: attr.summary,
275
+ description: attr.description,
276
+ inheritedFrom: attr.inheritedFrom,
277
+ type: attr.type,
278
+ default: attr.default,
279
+ deprecated: attr.deprecated,
280
+ static: false,
281
+ source: void 0,
282
+ readonly: false
283
+ };
284
+ }) || [];
285
+ const properties = getComponentPublicProperties(component).filter((prop) => {
286
+ return !attributes?.map((attr) => attr.propName).includes(prop.name);
287
+ }).map((prop) => {
288
+ return {
289
+ attrName: void 0,
290
+ propName: prop.name,
291
+ summary: prop.summary,
292
+ description: prop.description,
293
+ inheritedFrom: prop.inheritedFrom,
294
+ type: prop.type,
295
+ default: prop.default,
296
+ deprecated: prop.deprecated,
297
+ static: prop.static,
298
+ source: prop.source,
299
+ readonly: prop.readonly
300
+ };
301
+ });
302
+ return [...attributes, ...properties];
303
+ }
304
+ function getPropertyOnlyFields(component) {
305
+ if (!component) {
306
+ return [];
307
+ }
308
+ const props = getComponentPublicProperties(component) || [];
309
+ const attrs = component.attributes?.map((attr) => attr.name) || [];
310
+ return props?.filter(
311
+ (prop) => !attrs.includes(prop.name) || []
312
+ );
313
+ }
314
+ function getMemberDescription(description, deprecated) {
315
+ if (!deprecated) {
316
+ return description || "";
317
+ }
318
+ const desc = description ? `- ${description}` : "";
319
+ return typeof deprecated === "string" ? `@deprecated ${deprecated} ${desc}` : `@deprecated ${desc}`;
320
+ }
321
+ var defaultDescriptionOptions = {
322
+ order: [
323
+ "attrsAndProps",
324
+ "events",
325
+ "slots",
326
+ "methods",
327
+ "cssProps",
328
+ "cssParts",
329
+ "cssState"
330
+ ],
331
+ descriptionSrc: "description",
332
+ apis: {
333
+ attributes: {
334
+ heading: "Attributes",
335
+ description: "HTML attributes that can be applied to this element.",
336
+ template: (api) => api?.map((attr) => {
337
+ const getName = (attr2) => attr2.name === attr2.fieldName || !attr2.fieldName ? `\`${attr2.name}\`` : `\`${attr2.name}\`/\`${attr2.fieldName}\``;
338
+ return `- ${getName(attr)}: ${attr.description}`;
339
+ }).join("\n") || ""
340
+ },
341
+ properties: {
342
+ heading: "Properties",
343
+ description: "Properties that can be applied to this element using JavaScript.",
344
+ template: (api) => api?.map(
345
+ (prop) => `- \`${prop.name}\`: ${prop.readonly ? "(readonly) " : ""}${prop.description}`
346
+ ).join("\n") || ""
347
+ },
348
+ attrsAndProps: {
349
+ heading: "Attributes & Properties",
350
+ description: "Component attributes and properties that can be applied to the element or by using JavaScript.",
351
+ template: (api) => api?.map((prop) => {
352
+ const getName = (prop2) => prop2.attrName === prop2.propName || !prop2.attrName ? `\`${prop2.propName}\`` : `\`${prop2.attrName}\`/\`${prop2.propName}\``;
353
+ return `- ${getName(prop)}: ${prop.description} ${!prop.attrName ? "(property only)" : ""}${prop.readonly ? " (readonly)" : ""}`;
354
+ }).join("\n") || ""
355
+ },
356
+ propsOnly: {
357
+ heading: "Properties",
358
+ description: "Properties that can be applied to this element using JavaScript.",
359
+ template: (api) => api?.map(
360
+ (prop) => `- \`${prop.name}\`: ${prop.readonly ? "(readonly) " : ""}${prop.description}`
361
+ ).join("\n") || ""
362
+ },
363
+ events: {
364
+ heading: "Events",
365
+ description: "Events that will be emitted by the component.",
366
+ template: (api) => api?.map((event) => `- \`${event.name}\`: ${event.description}`).join("\n") || ""
367
+ },
368
+ methods: {
369
+ heading: "Methods",
370
+ description: "Methods that can be called to access component functionality.",
371
+ template: (api) => api?.map((method) => `- \`${method.type.text}\`: ${method.description}`).join("\n") || ""
372
+ },
373
+ slots: {
374
+ heading: "Slots",
375
+ description: "Areas where markup can be added to the component.",
376
+ template: (api) => api?.map(
377
+ (slot) => `- \`${slot.name || "(default)"}\`: ${slot.description}`
378
+ ).join("\n") || ""
379
+ },
380
+ cssProps: {
381
+ heading: "CSS Custom Properties",
382
+ description: "CSS variables available for styling the component.",
383
+ template: (api) => api?.map(
384
+ (cssProp) => `- \`${cssProp.name}\`: ${cssProp.description} (default: \`${cssProp.default}\`)`
385
+ ).join("\n") || ""
386
+ },
387
+ cssParts: {
388
+ heading: "CSS Parts",
389
+ description: "Custom selectors for styling elements within the component.",
390
+ template: (api) => api?.map((cssPart) => `- \`${cssPart.name}\`: ${cssPart.description}`).join("\n") || ""
391
+ },
392
+ cssState: {
393
+ heading: "CSS States",
394
+ description: "These can be used to apply styling when a component is in a given state.",
395
+ template: (api) => api?.map((cssState) => `- \`${cssState.name}\`: ${cssState.description}`).join("\n") || ""
396
+ }
397
+ }
398
+ };
399
+ function createMarkdownHeading(level) {
400
+ const safeLevel = Math.min(Math.max(level, 1), 6);
401
+ return "#".repeat(safeLevel);
402
+ }
403
+
404
+ // src/logger.ts
405
+ var Logger = class {
406
+ #debug;
407
+ constructor(debug = false) {
408
+ this.#debug = debug;
409
+ }
410
+ log(message, color = "\x1B[30m%s\x1B[0m") {
411
+ if (!this.#debug) {
412
+ return;
413
+ }
414
+ console.log(color, message);
415
+ }
416
+ red(message) {
417
+ this.log(message, "\x1B[31m%s\x1B[0m");
418
+ }
419
+ green(message) {
420
+ this.log(message, "\x1B[32m%s\x1B[0m");
421
+ }
422
+ yellow(message) {
423
+ this.log(message, "\x1B[33m%s\x1B[0m");
424
+ }
425
+ blue(message) {
426
+ this.log(message, "\x1B[34m%s\x1B[0m");
427
+ }
428
+ magenta(message) {
429
+ this.log(message, "\x1B[35m%s\x1B[0m");
430
+ }
431
+ cyan(message) {
432
+ this.log(message, "\x1B[36m%s\x1B[0m");
433
+ }
434
+ };
435
+
436
+ // src/global-types.ts
437
+ var GLOBAL_PROPS = `
438
+ /** Content added between the opening and closing tags of the element */
439
+ children?: any;
440
+ /** Used for declaratively styling one or more elements using CSS (Cascading Stylesheets) */
441
+ class?: string;
442
+ /** Takes an object where the key is the class name(s) and the value is a boolean expression. When true, the class is applied, and when false, it is removed. */
443
+ classList?: Record<string, boolean | undefined>;
444
+ /** Specifies the text direction of the element. */
445
+ dir?: "ltr" | "rtl";
446
+ /** Contains a space-separated list of the part names of the element that should be exposed on the host element. */
447
+ exportparts?: string;
448
+ /** Specifies whether the element should be hidden. */
449
+ hidden?: boolean | string;
450
+ /** A unique identifier for the element. */
451
+ id?: string;
452
+ /** Specifies the language of the element. */
453
+ lang?: string;
454
+ /** Defines the element's semantic role for accessibility APIs. */
455
+ role?: string;
456
+ /** Contains a space-separated list of the part names of the element. Part names allows CSS to select and style specific elements in a shadow tree via the ::part pseudo-element. */
457
+ part?: string;
458
+ /** Use the ref attribute with a variable to assign a DOM element to the variable once the element is rendered. */
459
+ ref?: unknown | ((e: unknown) => void);
460
+ /** Adds a reference for a custom element slot */
461
+ slot?: string;
462
+ /** Prop for setting inline styles */
463
+ style?: string;
464
+ /** Overrides the default Tab button behavior. Avoid using values other than -1 and 0. */
465
+ tabIndex?: number;
466
+ /** Specifies the tooltip text for the element. */
467
+ title?: string;
468
+ /** Passing 'no' excludes the element content from being translated. */
469
+ translate?: "yes" | "no";
470
+ /** The popover global attribute is used to designate an element as a popover element. */
471
+ popover?: "auto" | "hint" | "manual";
472
+ /** Turns an element element into a popover control button; takes the ID of the popover element to control as its value. */
473
+ popovertarget?: "top" | "bottom" | "left" | "right" | "auto";
474
+ /** Specifies the action to be performed on a popover element being controlled by a control element. */
475
+ popovertargetaction?: "show" | "hide" | "toggle";
476
+ `;
477
+ var GLOBAL_EVENTS = `
478
+ // Mouse Events
479
+
480
+ /** Triggered when the element is clicked by the user by mouse or keyboard. */
481
+ onClick?: (event: MouseEvent) => void;
482
+ /** Fired when the context menu is triggered, often by right-clicking. */
483
+ onContextMenu?: (event: MouseEvent) => void;
484
+ /** Fired when the element is double-clicked. */
485
+ onDoubleClick?: (event: MouseEvent) => void;
486
+ /** Fired repeatedly as the draggable element is being dragged. */
487
+ onDrag?: (event: DragEvent) => void;
488
+ /** Fired when the dragging of a draggable element is finished. */
489
+ onDragEnd?: (event: DragEvent) => void;
490
+ /** Fired when a dragged element or text selection enters a valid drop target. */
491
+ onDragEnter?: (event: DragEvent) => void;
492
+ /** Fired when a dragged element or text selection leaves a valid drop target. */
493
+ onDragExit?: (event: DragEvent) => void;
494
+ /** Fired when a dragged element or text selection leaves a valid drop target. */
495
+ onDragLeave?: (event: DragEvent) => void;
496
+ /** Fired when an element or text selection is being dragged over a valid drop target (every few hundred milliseconds). */
497
+ onDragOver?: (event: DragEvent) => void;
498
+ /** Fired when a draggable element starts being dragged. */
499
+ onDragStart?: (event: DragEvent) => void;
500
+ /** Fired when a dragged element is dropped onto a drop target. */
501
+ onDrop?: (event: DragEvent) => void;
502
+ /** Fired when a mouse button is pressed down on the element. */
503
+ onMouseDown?: (event: MouseEvent) => void;
504
+ /** Fired when the mouse cursor enters the element. */
505
+ onMouseEnter?: (event: MouseEvent) => void;
506
+ /** Triggered when the mouse cursor leaves the element. */
507
+ onMouseLeave?: (event: MouseEvent) => void;
508
+ /** Fired at an element when a pointing device (usually a mouse) is moved while the cursor's hotspot is inside it. */
509
+ onMouseMove?: (event: MouseEvent) => void;
510
+ /** Fired at an Element when a pointing device (usually a mouse) is used to move the cursor so that it is no longer contained within the element or one of its children. */
511
+ onMouseOut?: (event: MouseEvent) => void;
512
+ /** Fired at an Element when a pointing device (such as a mouse or trackpad) is used to move the cursor onto the element or one of its child elements. */
513
+ onMouseOver?: (event: MouseEvent) => void;
514
+ /** Fired when a mouse button is released on the element. */
515
+ onMouseUp?: (event: MouseEvent) => void;
516
+
517
+ // Keyboard Events
518
+
519
+ /** Fired when a key is pressed down. */
520
+ onKeyDown?: (event: KeyboardEvent) => void;
521
+ /** Fired when a key is released.. */
522
+ onKeyUp?: (event: KeyboardEvent) => void;
523
+ /** Fired when a key is pressed down. */
524
+ onKeyPressed?: (event: KeyboardEvent) => void;
525
+
526
+ // Focus Events
527
+
528
+ /** Fired when the element receives focus, often triggered by tab navigation. */
529
+ onFocus?: (event: FocusEvent) => void;
530
+ /** Fired when the element loses focus. */
531
+ onBlur?: (event: FocusEvent) => void;
532
+
533
+ // Form Events
534
+
535
+ /** Fired when the value of an input element changes, such as with text inputs or select elements. */
536
+ onChange?: (event: Event) => void;
537
+ /** Fires when the value of an <input>, <select>, or <textarea> element has been changed. */
538
+ onInput?: (event: Event) => void;
539
+ /** Fired when a form is submitted, usually on pressing Enter in a text input. */
540
+ onSubmit?: (event: Event) => void;
541
+ /** Fired when a form is reset. */
542
+ onReset?: (event: Event) => void;
543
+
544
+ // UI Events
545
+
546
+ /** Fired when the content of an element is scrolled. */
547
+ onScroll?: (event: UIEvent) => void;
548
+
549
+ // Wheel Events
550
+
551
+ /** Fired when the mouse wheel is scrolled while the element is focused. */
552
+ onWheel?: (event: WheelEvent) => void;
553
+
554
+ // Animation Events
555
+
556
+ /** Fired when a CSS animation starts. */
557
+ onAnimationStart?: (event: AnimationEvent) => void;
558
+ /** Fired when a CSS animation completes. */
559
+ onAnimationEnd?: (event: AnimationEvent) => void;
560
+ /** Fired when a CSS animation completes one iteration. */
561
+ onAnimationIteration?: (event: AnimationEvent) => void;
562
+
563
+ // Transition Events
564
+
565
+ /** Fired when a CSS transition has completed. */
566
+ onTransitionEnd?: (event: TransitionEvent) => void;
567
+
568
+ // Media Events
569
+
570
+ /** Fired when an element (usually an image) finishes loading */
571
+ onLoad?: (event: Event) => void;
572
+ /** Fired when an error occurs during the loading of an element, like an image not being found. */
573
+ onError?: (event: Event) => void;
574
+
575
+ // Clipboard Events
576
+
577
+ /** Fires when the user initiates a copy action through the browser's user interface. */
578
+ onCopy?: (event: ClipboardEvent) => void;
579
+ /** Fired when the user has initiated a "cut" action through the browser's user interface. */
580
+ onCut?: (event: ClipboardEvent) => void;
581
+ /** Fired when the user has initiated a "paste" action through the browser's user interface. */
582
+ onPaste?: (event: ClipboardEvent) => void;
583
+ `;
584
+
585
+ // src/type-generator.ts
586
+ var DEFAULT_OPTIONS = {
587
+ fileName: "custom-elements-svelte.d.ts",
588
+ outdir: "./",
589
+ exclude: [],
590
+ includeModernEventHandlers: true
591
+ };
592
+ function generateSvelteTypes(manifest2, options = {}) {
593
+ const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
594
+ const log = new Logger(mergedOptions.debug);
595
+ if (mergedOptions.skip) {
596
+ log.yellow("[svelte-types] - Skipped");
597
+ return;
598
+ }
599
+ if (!manifest2?.modules?.length) {
600
+ log.red("[svelte-types] - No modules found in the manifest.");
601
+ return;
602
+ }
603
+ if (!mergedOptions.outdir) {
604
+ log.red("[svelte-types] - No output directory specified.");
605
+ return;
606
+ }
607
+ const template = getTypeTemplate(manifest2, mergedOptions);
608
+ if (mergedOptions.fileName) {
609
+ createOutDir(mergedOptions.outdir);
610
+ const outputPath = saveFile(
611
+ mergedOptions.outdir,
612
+ mergedOptions.fileName,
613
+ template
614
+ );
615
+ log.green(`[svelte-types] - Generated "${outputPath}".`);
616
+ }
617
+ return template;
618
+ }
619
+ function getTypeTemplate(manifest2, options) {
620
+ const components2 = getAllComponents(manifest2, options.exclude).filter(
621
+ (component) => component.customElement && component.name && component.tagName
622
+ );
623
+ return `
624
+ ${getImports(manifest2, components2, options)}
625
+
626
+ type BaseProps = {
627
+ ${GLOBAL_PROPS}
628
+ };
629
+
630
+ type BaseEvents = {
631
+ ${options.globalEvents ?? ""}
632
+ ${options.includeDefaultDOMEvents ? getSvelteGlobalEvents(options.includeModernEventHandlers) : ""}
633
+ };
634
+
635
+ ${components2.map((component) => getComponentPropsTemplate(component, options)).join("\n")}
636
+ ${components2.map((component) => getComponentElementTemplate(component, options)).join("\n")}
637
+
638
+ export type CustomElements = {
639
+ ${components2.map((component) => {
640
+ const tagName = formatTagName(component.tagName, options);
641
+ return `
642
+ /**
643
+ ${getComponentDetailsTemplate(toUtilityComponent(component), options.componentDescriptionOptions, true)}
644
+ */
645
+ "${tagName}": Partial<${component.name}Props & BaseProps & BaseEvents>;`;
646
+ }).join("\n")}
647
+ };
648
+
649
+ declare namespace svelteHTML {
650
+ interface IntrinsicElements extends CustomElements {}
651
+ }
652
+ `;
653
+ }
654
+ function getImports(manifest2, components2, options) {
655
+ const names = /* @__PURE__ */ new Map();
656
+ for (const component of components2) {
657
+ const importPath = options.globalTypePath ? options.globalTypePath : typeof options.componentTypePath === "function" ? options.componentTypePath(
658
+ component.name,
659
+ component.tagName,
660
+ getComponentModulePath(manifest2, component)
661
+ ) : void 0;
662
+ if (!importPath) continue;
663
+ addImport(names, importPath, component.name);
664
+ for (const eventType of getCustomEventDetailTypes(
665
+ toUtilityComponent(component),
666
+ [component.name]
667
+ )) {
668
+ addImport(names, importPath, eventType);
669
+ }
670
+ }
671
+ return [...names.entries()].map(
672
+ ([importPath, exports]) => `import type { ${[...exports].join(", ")} } from "${importPath}";`
673
+ ).join("\n");
674
+ }
675
+ function getComponentPropsTemplate(component, options) {
676
+ const typeFor = (name, source, fallback) => {
677
+ if (options.globalTypePath || options.componentTypePath) {
678
+ return `${component.name}['${name}']`;
679
+ }
680
+ const configured = getConfiguredType(source, options.typesSrc);
681
+ return configured?.text || fallback?.text || "string";
682
+ };
683
+ const attributes = (component.attributes ?? []).map(
684
+ (attribute) => ` /** ${getMemberDescription(attribute.description, attribute.deprecated)} */
685
+ "${attribute.name}"?: ${typeFor(attribute.fieldName || attribute.name, attribute, attribute.type)};`
686
+ ).join("\n");
687
+ const publicProperties = getComponentPublicProperties(
688
+ toUtilityComponent(component)
689
+ ).filter((property) => !property.readonly && !property.static).filter(
690
+ (property) => !(component.attributes ?? []).some(
691
+ (attribute) => attribute.fieldName === property.name
692
+ )
693
+ );
694
+ const properties = publicProperties.map(
695
+ (property) => ` /** ${getMemberDescription(property.description, property.deprecated)} */
696
+ "${property.name}"?: ${typeFor(property.name, property, property.type)};`
697
+ ).join("\n");
698
+ const events = (component.events ?? []).map((event) => {
699
+ const eventType = event.type?.text || "Event";
700
+ const handlers = [` "on:${event.name}"?: (e: ${eventType}) => void;`];
701
+ if (options.includeModernEventHandlers) {
702
+ handlers.push(` "on${event.name}"?: (e: ${eventType}) => void;`);
703
+ }
704
+ return ` /** ${getMemberDescription(event.description, event.deprecated)} */
705
+ ${handlers.join("\n")}`;
706
+ }).join("\n");
707
+ const cssProperties = (component.cssProperties ?? []).map(
708
+ (property) => ` /** ${getMemberDescription(property.description, property.deprecated)} */
709
+ "style:${property.name}"?: string | number;`
710
+ ).join("\n");
711
+ return `export type ${component.name}Props = {
712
+ ${attributes}
713
+ ${properties}
714
+ ${events}
715
+ ${cssProperties}
716
+ };`;
717
+ }
718
+ function addImport(imports, importPath, name) {
719
+ if (!imports.has(importPath)) imports.set(importPath, /* @__PURE__ */ new Set());
720
+ imports.get(importPath).add(name);
721
+ }
722
+ function getComponentElementTemplate(component, options) {
723
+ const elementType = `${component.name}Element`;
724
+ const slots = component.slots?.map((slot) => JSON.stringify(slot.name)) ?? [];
725
+ const slotType = slots.length ? `export type ${component.name}Slots = ${slots.join(" | ")};` : "";
726
+ if (options.globalTypePath || options.componentTypePath) {
727
+ return `export type ${elementType} = ${component.name};
728
+ ${slotType}`;
729
+ }
730
+ const methods = getComponentPublicMethods(toUtilityComponent(component)).filter((method) => !method.static).map((method) => {
731
+ const parameters = (method.parameters ?? []).map((parameter) => {
732
+ const optional = parameter.optional ? "?" : "";
733
+ const rest = parameter.rest ? "..." : "";
734
+ return `${rest}${parameter.name}${optional}: ${parameter.type?.text || "unknown"}`;
735
+ }).join(", ");
736
+ return ` /** ${getMemberDescription(method.description, method.deprecated)} */
737
+ ${method.name}(${parameters}): ${method.return?.type?.text || "void"};`;
738
+ }).join("\n");
739
+ return `export interface ${elementType} extends HTMLElement {
740
+ ${methods}
741
+ }
742
+ ${slotType}`;
743
+ }
744
+ function formatTagName(tagName, options) {
745
+ return options.tagFormatter ? options.tagFormatter(tagName) : tagName;
746
+ }
747
+ function toUtilityComponent(component) {
748
+ return component;
749
+ }
750
+ function getConfiguredType(source, sourceKey) {
751
+ if (!sourceKey || !source || typeof source !== "object") return void 0;
752
+ const value = source[sourceKey];
753
+ return value && typeof value === "object" && "text" in value ? value : void 0;
754
+ }
755
+ function getComponentModulePath(manifest2, component) {
756
+ return manifest2.modules.find(
757
+ (module) => module.declarations?.some(
758
+ (declaration) => declaration.name === component.name
759
+ )
760
+ )?.path;
761
+ }
762
+ function getSvelteGlobalEvents(includeModern) {
763
+ return GLOBAL_EVENTS.replace(
764
+ /^(\s*)on([A-Z][\w]*)(\?:.*)$/gm,
765
+ (_, indent, name, declaration) => {
766
+ const eventName = name.toLowerCase();
767
+ const handlers = [`${indent}"on:${eventName}"${declaration}`];
768
+ if (includeModern) handlers.push(`${indent}on${eventName}${declaration}`);
769
+ return handlers.join("\n");
770
+ }
771
+ );
772
+ }
773
+ function createOutDir(outDir) {
774
+ if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
775
+ }
776
+ function saveFile(outDir, fileName, contents) {
777
+ const outputPath = path.join(outDir, fileName);
778
+ fs.writeFileSync(
779
+ outputPath,
780
+ prettier.format(contents, { parser: "typescript", printWidth: 120 })
781
+ );
782
+ return outputPath;
783
+ }
784
+
785
+ // src/cem-plugin.ts
786
+ function customElementSveltePlugin(options = {}) {
787
+ return {
788
+ name: "@wc-toolkit/svelte-types",
789
+ packageLinkPhase({ customElementsManifest }) {
790
+ generateSvelteTypes(customElementsManifest, options);
791
+ }
792
+ };
793
+ }
794
+ export {
795
+ customElementSveltePlugin,
796
+ generateSvelteTypes
797
+ };