@wc-toolkit/vuejs-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/LICENSE +21 -0
- package/README.md +165 -0
- package/dist/index.cjs +675 -0
- package/dist/index.d.cts +814 -0
- package/dist/index.d.ts +814 -0
- package/dist/index.js +637 -0
- package/package.json +86 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,637 @@
|
|
|
1
|
+
// src/type-generator.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
// node_modules/.pnpm/@wc-toolkit+cem-utilities@1.4.1/node_modules/@wc-toolkit/cem-utilities/dist/index.js
|
|
6
|
+
var definitionExports = /* @__PURE__ */ new Map();
|
|
7
|
+
var components = [];
|
|
8
|
+
var manifest;
|
|
9
|
+
function getAllComponents(customElementsManifest, exclude = []) {
|
|
10
|
+
if (!customElementsManifest) {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
if (!customElementsManifest || areObjectsEqual(customElementsManifest, manifest)) {
|
|
14
|
+
return components;
|
|
15
|
+
}
|
|
16
|
+
resetCache();
|
|
17
|
+
manifest = customElementsManifest;
|
|
18
|
+
setAllDefinitionExports(customElementsManifest);
|
|
19
|
+
manifest.modules.forEach((module) => {
|
|
20
|
+
const ces = module.declarations?.filter(
|
|
21
|
+
(d) => d.customElement
|
|
22
|
+
);
|
|
23
|
+
if (ces?.length) {
|
|
24
|
+
ces.forEach((ce) => {
|
|
25
|
+
if (exclude?.includes(ce.name)) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
ce.modulePath = module.path;
|
|
29
|
+
ce.definitionPath = definitionExports.get(ce.name);
|
|
30
|
+
if ("typeDefinitionPath" in module && module.typeDefinitionPath) {
|
|
31
|
+
ce.typeDefinitionPath = module.typeDefinitionPath;
|
|
32
|
+
}
|
|
33
|
+
components.push(ce);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
return components;
|
|
38
|
+
}
|
|
39
|
+
function resetCache() {
|
|
40
|
+
components = [];
|
|
41
|
+
manifest = void 0;
|
|
42
|
+
definitionExports.clear();
|
|
43
|
+
}
|
|
44
|
+
function getComponentPublicProperties(component) {
|
|
45
|
+
if (!component || !component.members) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
return component?.members?.filter(
|
|
49
|
+
(member) => member.kind === "field" && member.privacy !== "private" && member.privacy !== "protected" && !member.static && !member.name.startsWith("#")
|
|
50
|
+
) || [];
|
|
51
|
+
}
|
|
52
|
+
function setAllDefinitionExports(customElementsManifest) {
|
|
53
|
+
if (!customElementsManifest) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
customElementsManifest.modules.forEach((mod) => {
|
|
57
|
+
const defExports = mod?.exports?.filter(
|
|
58
|
+
(e) => e.kind === "custom-element-definition"
|
|
59
|
+
);
|
|
60
|
+
if (defExports?.length) {
|
|
61
|
+
defExports.forEach((e) => {
|
|
62
|
+
if (e.declaration.name) {
|
|
63
|
+
definitionExports.set(e.declaration.name, mod.path);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function areObjectsEqual(obj1, obj2) {
|
|
70
|
+
if (obj1 === obj2) return true;
|
|
71
|
+
if (obj1 === null || obj2 === null || typeof obj1 !== "object" || typeof obj2 !== "object")
|
|
72
|
+
return false;
|
|
73
|
+
if (Array.isArray(obj1) && Array.isArray(obj2)) {
|
|
74
|
+
if (obj1.length !== obj2.length) return false;
|
|
75
|
+
return obj1.every((item, index) => areObjectsEqual(item, obj2[index]));
|
|
76
|
+
}
|
|
77
|
+
const keys1 = Object.keys(obj1);
|
|
78
|
+
const keys2 = Object.keys(obj2);
|
|
79
|
+
if (keys1.length !== keys2.length) return false;
|
|
80
|
+
if (!keys2.every((key) => key in obj1)) return false;
|
|
81
|
+
return keys1.every((key) => {
|
|
82
|
+
const val1 = obj1[key];
|
|
83
|
+
const val2 = obj2[key];
|
|
84
|
+
if (val1 === null && val2 === null) return true;
|
|
85
|
+
if (val1 === null || val2 === null) return false;
|
|
86
|
+
if (typeof val1 === "object" && typeof val2 === "object") {
|
|
87
|
+
return areObjectsEqual(val1, val2);
|
|
88
|
+
}
|
|
89
|
+
return val1 === val2;
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function getMemberDescription(description, deprecated) {
|
|
93
|
+
if (!deprecated) {
|
|
94
|
+
return description || "";
|
|
95
|
+
}
|
|
96
|
+
const desc = description ? `- ${description}` : "";
|
|
97
|
+
return typeof deprecated === "string" ? `@deprecated ${deprecated} ${desc}` : `@deprecated ${desc}`;
|
|
98
|
+
}
|
|
99
|
+
function toPascalCase(value) {
|
|
100
|
+
return value.replace(new RegExp(/[-_]+/, "g"), " ").replace(new RegExp(/[^\w\s]/, "g"), "").replace(
|
|
101
|
+
new RegExp(/\s+(.)(\w*)/, "g"),
|
|
102
|
+
($1, $2, $3) => `${$2.toUpperCase() + $3}`
|
|
103
|
+
).replace(new RegExp(/\w/), (s) => s.toUpperCase());
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/logger.ts
|
|
107
|
+
var Logger = class {
|
|
108
|
+
#debug;
|
|
109
|
+
constructor(debug = false) {
|
|
110
|
+
this.#debug = debug;
|
|
111
|
+
}
|
|
112
|
+
log(message, color = "\x1B[30m%s\x1B[0m") {
|
|
113
|
+
if (!this.#debug) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
console.log(color, message);
|
|
117
|
+
}
|
|
118
|
+
red(message) {
|
|
119
|
+
this.log(message, "\x1B[31m%s\x1B[0m");
|
|
120
|
+
}
|
|
121
|
+
green(message) {
|
|
122
|
+
this.log(message, "\x1B[32m%s\x1B[0m");
|
|
123
|
+
}
|
|
124
|
+
yellow(message) {
|
|
125
|
+
this.log(message, "\x1B[33m%s\x1B[0m");
|
|
126
|
+
}
|
|
127
|
+
blue(message) {
|
|
128
|
+
this.log(message, "\x1B[34m%s\x1B[0m");
|
|
129
|
+
}
|
|
130
|
+
magenta(message) {
|
|
131
|
+
this.log(message, "\x1B[35m%s\x1B[0m");
|
|
132
|
+
}
|
|
133
|
+
cyan(message) {
|
|
134
|
+
this.log(message, "\x1B[36m%s\x1B[0m");
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// src/type-generator.ts
|
|
139
|
+
import prettier from "@prettier/sync";
|
|
140
|
+
var DEFAULT_OPTIONS = {
|
|
141
|
+
fileName: "custom-element-vuejs.d.ts",
|
|
142
|
+
outdir: "./",
|
|
143
|
+
exclude: [],
|
|
144
|
+
prefix: "",
|
|
145
|
+
suffix: ""
|
|
146
|
+
};
|
|
147
|
+
var KNOWN_FILE_EXTENSIONS = [
|
|
148
|
+
".d.ts",
|
|
149
|
+
".ts",
|
|
150
|
+
".tsx",
|
|
151
|
+
".js",
|
|
152
|
+
".jsx",
|
|
153
|
+
".mjs",
|
|
154
|
+
".cjs",
|
|
155
|
+
".mts",
|
|
156
|
+
".cts"
|
|
157
|
+
];
|
|
158
|
+
function toPosixPath(p) {
|
|
159
|
+
return p.split(path.sep).join("/");
|
|
160
|
+
}
|
|
161
|
+
function ensureRelativeSpecifier(p) {
|
|
162
|
+
return p.startsWith(".") ? p : `./${p}`;
|
|
163
|
+
}
|
|
164
|
+
function normalizeImportPath(importPath, options) {
|
|
165
|
+
const outDirAbs = path.resolve(options.outdir ?? "./");
|
|
166
|
+
const isAbsPath = importPath.startsWith("/") || /^[A-Za-z]:[\\/]/.test(importPath);
|
|
167
|
+
const hasPathSeparators = importPath.includes("/") || importPath.includes("\\");
|
|
168
|
+
const hasKnownExt = KNOWN_FILE_EXTENSIONS.some(
|
|
169
|
+
(ext) => importPath.endsWith(ext)
|
|
170
|
+
);
|
|
171
|
+
const shouldTryFs = isAbsPath || importPath.startsWith(".") || hasPathSeparators || hasKnownExt;
|
|
172
|
+
if (!shouldTryFs) {
|
|
173
|
+
return importPath;
|
|
174
|
+
}
|
|
175
|
+
const abs = path.resolve(importPath);
|
|
176
|
+
if (!fs.existsSync(abs)) {
|
|
177
|
+
return importPath;
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
if (!fs.statSync(abs).isFile()) {
|
|
181
|
+
return importPath;
|
|
182
|
+
}
|
|
183
|
+
} catch {
|
|
184
|
+
return importPath;
|
|
185
|
+
}
|
|
186
|
+
const rel = toPosixPath(path.relative(outDirAbs, abs));
|
|
187
|
+
return ensureRelativeSpecifier(rel);
|
|
188
|
+
}
|
|
189
|
+
function generateVuejsTypes(manifest2, options = {}) {
|
|
190
|
+
const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
|
|
191
|
+
const log = new Logger(mergedOptions.debug);
|
|
192
|
+
if (mergedOptions.skip) {
|
|
193
|
+
log.yellow("[vuejs-types] - Skipped");
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (!manifest2 || !manifest2.modules || manifest2.modules.length === 0) {
|
|
197
|
+
log.red("[vuejs-types] - No modules found in the manifest.");
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (!mergedOptions.outdir) {
|
|
201
|
+
log.red("[vuejs-types] - No output directory specified.");
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
log.log("[vuejs-types] - Generating types...");
|
|
205
|
+
const template = getTypeTemplate(manifest2, mergedOptions);
|
|
206
|
+
if (mergedOptions.fileName) {
|
|
207
|
+
createOutDir(mergedOptions.outdir);
|
|
208
|
+
const outputPath = saveFile(
|
|
209
|
+
mergedOptions.outdir,
|
|
210
|
+
mergedOptions.fileName,
|
|
211
|
+
template
|
|
212
|
+
);
|
|
213
|
+
log.green(`[vuejs-types] - Generated "${outputPath}".`);
|
|
214
|
+
} else {
|
|
215
|
+
log.yellow(
|
|
216
|
+
`[vuejs-types] - File generation skipped because \`fileName\` was not defined.`
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
return template;
|
|
220
|
+
}
|
|
221
|
+
function getImports(manifest2, options) {
|
|
222
|
+
const imports = /* @__PURE__ */ new Map();
|
|
223
|
+
const componentModules = /* @__PURE__ */ new Map();
|
|
224
|
+
manifest2.modules.forEach((module) => {
|
|
225
|
+
if (!module.declarations || !module.declarations.length || !module.declarations.some((d) => d.customElement)) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
module.declarations?.forEach((element) => {
|
|
229
|
+
const component = element;
|
|
230
|
+
if (!component.customElement || !component.name) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
componentModules.set(component.name, {
|
|
234
|
+
modulePath: module.path,
|
|
235
|
+
tagName: component.tagName
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
if (options.globalTypePath) {
|
|
239
|
+
module.exports?.forEach((exportDeclaration) => {
|
|
240
|
+
const exportName = exportDeclaration.declaration.name;
|
|
241
|
+
if (!exportName || exportName === "*") {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
addImport(imports, options.globalTypePath, exportName);
|
|
245
|
+
});
|
|
246
|
+
} else {
|
|
247
|
+
module.declarations?.forEach((element) => {
|
|
248
|
+
const component = element;
|
|
249
|
+
if (!component.customElement || !component.name) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const importPath = normalizeImportPath(
|
|
253
|
+
getComponentImportPath(
|
|
254
|
+
component.name,
|
|
255
|
+
component.tagName,
|
|
256
|
+
module.path,
|
|
257
|
+
options
|
|
258
|
+
),
|
|
259
|
+
options
|
|
260
|
+
);
|
|
261
|
+
module.exports?.forEach((exportDeclaration) => {
|
|
262
|
+
const exportName = exportDeclaration.declaration.name;
|
|
263
|
+
if (!exportName || exportName === "*") {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (!(options.defaultExport && exportName === component.name)) {
|
|
267
|
+
addImport(imports, importPath, exportName);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
if (options.defaultExport) {
|
|
271
|
+
addImport(imports, importPath, `default as ${component.name}`);
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
if (options.useCemTypes) {
|
|
277
|
+
getAllComponents(manifest2, options.exclude).forEach((component) => {
|
|
278
|
+
if (!component.name) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const componentModule = componentModules.get(component.name);
|
|
282
|
+
if (!componentModule) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
getComponentProps(component).forEach((prop) => {
|
|
286
|
+
const propType = getResolvedPropType(prop, options);
|
|
287
|
+
propType?.references?.forEach((reference) => {
|
|
288
|
+
if (!reference.name || reference.name === "default") {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const importPath = getTypeImportPath(
|
|
292
|
+
reference,
|
|
293
|
+
componentModule.modulePath,
|
|
294
|
+
component,
|
|
295
|
+
options
|
|
296
|
+
);
|
|
297
|
+
if (!importPath) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
addImport(imports, importPath, reference.name);
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
return Array.from(imports.entries()).map(
|
|
306
|
+
([importPath, exportNames]) => `import type { ${Array.from(exportNames).join(", ")} } from "${importPath}";`
|
|
307
|
+
).join("\n");
|
|
308
|
+
}
|
|
309
|
+
function getTypeTemplate(manifest2, options) {
|
|
310
|
+
const components2 = getAllComponents(manifest2, options.exclude);
|
|
311
|
+
const imports = getImports(manifest2, options);
|
|
312
|
+
return `
|
|
313
|
+
${imports}
|
|
314
|
+
import type { HTMLAttributes, PublicProps, EmitFn, EmitsToProps } from "vue";
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* This file was autogenerated by @wc-toolkit/vuejs-types
|
|
318
|
+
${options.stronglyTypedEvents ? `/**
|
|
319
|
+
* A generic type for strongly typing custom events with their targets
|
|
320
|
+
* @template T - The type of the event target (extends EventTarget)
|
|
321
|
+
* @template D - The type of the detail payload for the custom event
|
|
322
|
+
*/
|
|
323
|
+
type TypedEvent<
|
|
324
|
+
T extends EventTarget,
|
|
325
|
+
E = Event
|
|
326
|
+
> = E & {
|
|
327
|
+
target: T;
|
|
328
|
+
};` : ""}
|
|
329
|
+
|
|
330
|
+
export type EventMap = {
|
|
331
|
+
[event: string]: Event;
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
// Vue's template type-checking reads props from $props and events from $emit.
|
|
335
|
+
// See: https://vuejs.org/guide/extras/web-components.html#non-vue-web-components-and-typescript
|
|
336
|
+
export type VueEmitsOptions<T extends EventMap> = {
|
|
337
|
+
[K in keyof T]: (event: T[K]) => void;
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
export type VueEmit<T extends EventMap> = EmitFn<VueEmitsOptions<T>>;
|
|
341
|
+
|
|
342
|
+
// Helps Volar autocomplete "@event" by providing "onXxx" props.
|
|
343
|
+
export type VueOnProps<T extends EventMap> = EmitsToProps<VueEmitsOptions<T>>;
|
|
344
|
+
|
|
345
|
+
export type DefineCustomElement<
|
|
346
|
+
ElementType extends HTMLElement,
|
|
347
|
+
Props = {},
|
|
348
|
+
Events extends EventMap = {},
|
|
349
|
+
> = new () => ElementType & {
|
|
350
|
+
/** @deprecated Do not use the $props property on a Custom Element ref; this is for template prop types only. */
|
|
351
|
+
$props: HTMLAttributes & Props & PublicProps & VueOnProps<Events>${options.allowUnknownProps ? " & Record<string, any>" : ""};
|
|
352
|
+
|
|
353
|
+
/** @deprecated Do not use the $emit property on a Custom Element ref; this is for template event types only. */
|
|
354
|
+
$emit: VueEmit<Events>;
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
${components2?.map((component) => {
|
|
358
|
+
if (!component.name || !component.tagName) {
|
|
359
|
+
return "";
|
|
360
|
+
}
|
|
361
|
+
const cachedProps = getComponentProps(component)?.filter(
|
|
362
|
+
(prop) => !prop.readonly && !prop.static
|
|
363
|
+
) || [];
|
|
364
|
+
const strongEventTypes = getStrongEventTypes(component);
|
|
365
|
+
const vueEventsTemplate = component.events?.filter((e) => e.name)?.map((event) => {
|
|
366
|
+
const eventType = event.type?.text?.startsWith("{") ? `CustomEvent<${event.type.text}>` : event.type?.text || "Event";
|
|
367
|
+
const resolvedEventType = getEventTypeName(
|
|
368
|
+
eventType,
|
|
369
|
+
strongEventTypes?.find((x) => x.name === event.name)?.newType || null,
|
|
370
|
+
component.name,
|
|
371
|
+
options.stronglyTypedEvents
|
|
372
|
+
);
|
|
373
|
+
return ` /** ${getMemberDescription(
|
|
374
|
+
event.description,
|
|
375
|
+
event.deprecated
|
|
376
|
+
)} */
|
|
377
|
+
"${event.name}": ${resolvedEventType};`;
|
|
378
|
+
}).join("\n") || "";
|
|
379
|
+
return `
|
|
380
|
+
${options.stronglyTypedEvents ? getStronglyTypedEvents(component) : ""}
|
|
381
|
+
|
|
382
|
+
export type ${component.name}VueProps = {
|
|
383
|
+
${(() => {
|
|
384
|
+
if (!cachedProps?.length) {
|
|
385
|
+
return "";
|
|
386
|
+
}
|
|
387
|
+
return cachedProps.reduce((acc, prop) => {
|
|
388
|
+
const description = getMemberDescription(prop.description, prop.deprecated);
|
|
389
|
+
const typeInfo = getResolvedPropType(prop, options);
|
|
390
|
+
const type = getPropType(component.name, prop, typeInfo, options);
|
|
391
|
+
const propExists = prop.propName ? acc.includes(` "${prop.propName}"?:`) : false;
|
|
392
|
+
const attrExists = prop.attrName ? acc.includes(` "${prop.attrName}"?:`) : false;
|
|
393
|
+
let result = acc;
|
|
394
|
+
if (prop.attrName && prop.attrName !== prop.propName && !attrExists) {
|
|
395
|
+
result += ` /** ${description} */
|
|
396
|
+
"${prop.attrName}"?: ${type};
|
|
397
|
+
`;
|
|
398
|
+
}
|
|
399
|
+
if (prop.propName && !propExists) {
|
|
400
|
+
result += ` /** ${description} */
|
|
401
|
+
"${prop.propName}"?: ${type};
|
|
402
|
+
`;
|
|
403
|
+
}
|
|
404
|
+
return result;
|
|
405
|
+
}, "");
|
|
406
|
+
})()}
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
export type ${component.name}VueEvents = {
|
|
410
|
+
${vueEventsTemplate}
|
|
411
|
+
};
|
|
412
|
+
`;
|
|
413
|
+
}).join("\n")}
|
|
414
|
+
|
|
415
|
+
export type CustomCssProperties = {
|
|
416
|
+
${(() => {
|
|
417
|
+
const uniqueCssProperties = /* @__PURE__ */ new Set();
|
|
418
|
+
const cssPropertiesArray = [];
|
|
419
|
+
components2.forEach((component) => {
|
|
420
|
+
component.cssProperties?.forEach((property) => {
|
|
421
|
+
if (!uniqueCssProperties.has(property.name)) {
|
|
422
|
+
uniqueCssProperties.add(property.name);
|
|
423
|
+
cssPropertiesArray.push(
|
|
424
|
+
` /** ${getMemberDescription(property.description, property.deprecated)} */
|
|
425
|
+
"${property.name}"?: string;`
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
return cssPropertiesArray.join("\n");
|
|
431
|
+
})()}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Vue SFC template type-checking (GlobalComponents) for non-Vue custom elements.
|
|
435
|
+
// Note: Some tooling expects this augmentation under "@vue/runtime-core", while
|
|
436
|
+
// other docs/examples use "vue". We emit both for compatibility.
|
|
437
|
+
export interface WcToolkitVueGlobalComponents {
|
|
438
|
+
${components2.map((component) => {
|
|
439
|
+
if (!component.name || !component.tagName) {
|
|
440
|
+
return "";
|
|
441
|
+
}
|
|
442
|
+
let tagName = component.tagName;
|
|
443
|
+
if (options.tagFormatter) {
|
|
444
|
+
tagName = options.tagFormatter(component.tagName);
|
|
445
|
+
} else if (options.prefix || options.suffix) {
|
|
446
|
+
tagName = `${options.prefix}${component.tagName}${options.suffix}`;
|
|
447
|
+
}
|
|
448
|
+
const componentDoc = component.description ? getMemberDescription(
|
|
449
|
+
component.description,
|
|
450
|
+
component.deprecated
|
|
451
|
+
).replace(/\n/g, " ").replace(/`/g, "'") : void 0;
|
|
452
|
+
return componentDoc ? ` /** ${componentDoc} */
|
|
453
|
+
"${tagName}": DefineCustomElement<${component.name}, ${component.name}VueProps, ${component.name}VueEvents>;` : ` "${tagName}": DefineCustomElement<${component.name}, ${component.name}VueProps, ${component.name}VueEvents>;`;
|
|
454
|
+
}).join("\n")}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
declare module "@vue/runtime-core" {
|
|
458
|
+
interface GlobalComponents extends WcToolkitVueGlobalComponents {}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
declare module "@vue/runtime-dom" {
|
|
462
|
+
interface GlobalComponents extends WcToolkitVueGlobalComponents {}
|
|
463
|
+
|
|
464
|
+
// Needed for named slots on native elements when using Web Components.
|
|
465
|
+
// Vue templates otherwise reject: <span slot="icon" />
|
|
466
|
+
interface HTMLAttributes {
|
|
467
|
+
slot?: string;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
declare module "vue" {
|
|
472
|
+
interface GlobalComponents extends WcToolkitVueGlobalComponents {}
|
|
473
|
+
|
|
474
|
+
// Some package managers (notably pnpm) may not make "@vue/runtime-dom" directly
|
|
475
|
+
// resolvable from the consuming project, so we also augment via "vue".
|
|
476
|
+
interface HTMLAttributes {
|
|
477
|
+
slot?: string;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
${options.excludeCssCustomProperties ? "" : "interface CSSProperties extends CustomCssProperties {}"}
|
|
481
|
+
}
|
|
482
|
+
`;
|
|
483
|
+
}
|
|
484
|
+
function addImport(imports, importPath, exportName) {
|
|
485
|
+
const existing = imports.get(importPath);
|
|
486
|
+
if (existing) {
|
|
487
|
+
existing.add(exportName);
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
imports.set(importPath, /* @__PURE__ */ new Set([exportName]));
|
|
491
|
+
}
|
|
492
|
+
function getComponentImportPath(componentName, tagName, modulePath, options) {
|
|
493
|
+
return typeof options.componentTypePath === "function" ? options.componentTypePath(componentName, tagName, modulePath) : modulePath;
|
|
494
|
+
}
|
|
495
|
+
function getTypeImportPath(reference, componentModulePath, component, options) {
|
|
496
|
+
if (reference.package) {
|
|
497
|
+
return reference.package;
|
|
498
|
+
}
|
|
499
|
+
if (!reference.module) {
|
|
500
|
+
return null;
|
|
501
|
+
}
|
|
502
|
+
if (reference.module === componentModulePath) {
|
|
503
|
+
if (options.globalTypePath) {
|
|
504
|
+
return normalizeImportPath(options.globalTypePath, options);
|
|
505
|
+
}
|
|
506
|
+
if (component.name) {
|
|
507
|
+
return normalizeImportPath(
|
|
508
|
+
getComponentImportPath(
|
|
509
|
+
component.name,
|
|
510
|
+
component.tagName,
|
|
511
|
+
componentModulePath,
|
|
512
|
+
options
|
|
513
|
+
),
|
|
514
|
+
options
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return normalizeImportPath(reference.module, options);
|
|
519
|
+
}
|
|
520
|
+
function getComponentProps(component) {
|
|
521
|
+
const properties = getComponentPublicProperties(
|
|
522
|
+
component
|
|
523
|
+
);
|
|
524
|
+
const propertyMap = new Map(
|
|
525
|
+
properties.map((property) => [property.name, property])
|
|
526
|
+
);
|
|
527
|
+
const attributeProps = component.attributes?.map(
|
|
528
|
+
(attribute) => ({
|
|
529
|
+
attrName: attribute.name,
|
|
530
|
+
propName: attribute.fieldName,
|
|
531
|
+
description: attribute.description,
|
|
532
|
+
deprecated: attribute.deprecated,
|
|
533
|
+
readonly: false,
|
|
534
|
+
static: false,
|
|
535
|
+
type: attribute.type,
|
|
536
|
+
attribute,
|
|
537
|
+
property: attribute.fieldName ? propertyMap.get(attribute.fieldName) : void 0
|
|
538
|
+
})
|
|
539
|
+
) || [];
|
|
540
|
+
const attributePropNames = new Set(
|
|
541
|
+
attributeProps.map((attribute) => attribute.propName).filter((propName) => Boolean(propName))
|
|
542
|
+
);
|
|
543
|
+
const propertyOnlyProps = properties.filter((property) => !attributePropNames.has(property.name)).map((property) => ({
|
|
544
|
+
attrName: void 0,
|
|
545
|
+
propName: property.name,
|
|
546
|
+
description: property.description,
|
|
547
|
+
deprecated: property.deprecated,
|
|
548
|
+
readonly: property.readonly,
|
|
549
|
+
static: property.static,
|
|
550
|
+
type: property.type,
|
|
551
|
+
attribute: void 0,
|
|
552
|
+
property
|
|
553
|
+
}));
|
|
554
|
+
return [...attributeProps, ...propertyOnlyProps];
|
|
555
|
+
}
|
|
556
|
+
function getTypeFromSource(source, sourceKey) {
|
|
557
|
+
const candidate = source ? source[sourceKey] : void 0;
|
|
558
|
+
if (candidate && typeof candidate === "object" && "text" in candidate && typeof candidate.text === "string") {
|
|
559
|
+
return candidate;
|
|
560
|
+
}
|
|
561
|
+
return void 0;
|
|
562
|
+
}
|
|
563
|
+
function getResolvedPropType(prop, options) {
|
|
564
|
+
const sourceKey = options.typesSrc || "type";
|
|
565
|
+
return getTypeFromSource(prop.property, sourceKey) ?? getTypeFromSource(prop.attribute, sourceKey) ?? (sourceKey === "type" ? void 0 : getTypeFromSource(prop.property, "type")) ?? (sourceKey === "type" ? void 0 : getTypeFromSource(prop.attribute, "type")) ?? prop.type;
|
|
566
|
+
}
|
|
567
|
+
function getPropType(componentName, prop, propType, options) {
|
|
568
|
+
if (options.useCemTypes) {
|
|
569
|
+
return propType?.text || "unknown";
|
|
570
|
+
}
|
|
571
|
+
return prop.propName ? `${componentName}['${prop.propName}']` : "unknown";
|
|
572
|
+
}
|
|
573
|
+
function getEventTypeName(eventType, strongEventType, componentName = "", stronglyTyped) {
|
|
574
|
+
return stronglyTyped ? strongEventType ?? `${componentName}ElementEvent` : eventType;
|
|
575
|
+
}
|
|
576
|
+
function getStrongEventTypes(component) {
|
|
577
|
+
const eventTypes = component?.events?.filter((e) => e.name)?.map((event) => ({
|
|
578
|
+
name: event.name,
|
|
579
|
+
type: event?.type?.text
|
|
580
|
+
}));
|
|
581
|
+
if (!eventTypes) {
|
|
582
|
+
return [];
|
|
583
|
+
}
|
|
584
|
+
return eventTypes.filter(
|
|
585
|
+
(eventType) => eventType.type && eventType.type !== "Event" && eventType.type !== "CustomEvent"
|
|
586
|
+
).map((eventType) => {
|
|
587
|
+
return {
|
|
588
|
+
name: eventType.name,
|
|
589
|
+
type: eventType.type.startsWith("{") ? `CustomEvent<${eventType.type}>` : eventType.type,
|
|
590
|
+
newType: `${component.name}${toPascalCase(eventType.name)}ElementEvent`
|
|
591
|
+
};
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
function getStronglyTypedEvents(component) {
|
|
595
|
+
if (!component.events?.length) {
|
|
596
|
+
return "";
|
|
597
|
+
}
|
|
598
|
+
const eventTypes = getStrongEventTypes(component);
|
|
599
|
+
const types = [
|
|
600
|
+
`/** \`${component.name}\` component event */
|
|
601
|
+
export type ${component.name}ElementEvent<E = Event> = TypedEvent<${component.name}, E>;`
|
|
602
|
+
];
|
|
603
|
+
eventTypes.forEach((eventType) => {
|
|
604
|
+
types.push(
|
|
605
|
+
`/** \`${eventType.name}\` event type */
|
|
606
|
+
export type ${eventType.newType} = ${component.name}ElementEvent<${eventType.type}>;`
|
|
607
|
+
);
|
|
608
|
+
});
|
|
609
|
+
return types.join("\n");
|
|
610
|
+
}
|
|
611
|
+
function createOutDir(outDir) {
|
|
612
|
+
if (outDir !== "./" && !fs.existsSync(outDir)) {
|
|
613
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
function saveFile(outDir, fileName, contents) {
|
|
617
|
+
const outputPath = path.join(outDir, fileName);
|
|
618
|
+
fs.writeFileSync(
|
|
619
|
+
outputPath,
|
|
620
|
+
prettier.format(contents, { parser: "typescript", printWidth: 80 })
|
|
621
|
+
);
|
|
622
|
+
return outputPath;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// src/cem-plugin.ts
|
|
626
|
+
function vuejsTypesPlugin(options = {}) {
|
|
627
|
+
return {
|
|
628
|
+
name: "@wc-toolkit/vuejs-types",
|
|
629
|
+
packageLinkPhase({ customElementsManifest }) {
|
|
630
|
+
generateVuejsTypes(customElementsManifest, options);
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
export {
|
|
635
|
+
generateVuejsTypes,
|
|
636
|
+
vuejsTypesPlugin
|
|
637
|
+
};
|