@zeus-js/component-analyzer 0.1.0-beta.3 → 0.1.0-beta.5

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.
@@ -1,10 +1,10 @@
1
1
  /**
2
- * component-analyzer v0.1.0-beta.3
2
+ * component-analyzer v0.1.0-beta.5
3
3
  * (c) 2026 baicie
4
4
  * Released under the MIT License.
5
5
  **/
6
- import { parse } from "@babel/parser";
7
6
  import * as t from "@babel/types";
7
+ import { parse } from "@babel/parser";
8
8
  import fs from "node:fs/promises";
9
9
  import path from "node:path";
10
10
  import fg from "fast-glob";
@@ -151,24 +151,144 @@ function uniqueSorted(values) {
151
151
  return Array.from(new Set(values)).sort();
152
152
  }
153
153
  //#endregion
154
+ //#region packages/web-c/component-analyzer/src/extractEmits.ts
155
+ function extractEmits(options) {
156
+ const emitsNode = options ? getObjectProperty(options, "emits") : void 0;
157
+ if (!t.isObjectExpression(emitsNode)) return {};
158
+ const events = {};
159
+ for (const member of emitsNode.properties) {
160
+ if (!t.isObjectProperty(member) || member.computed) continue;
161
+ const key = getObjectKey(member.key);
162
+ if (!key) continue;
163
+ events[key] = extractEventDefinition(key, member.value);
164
+ }
165
+ return events;
166
+ }
167
+ function createComponentEvent(key, detail) {
168
+ return {
169
+ key,
170
+ name: toKebabCase$1(key),
171
+ reactName: toReactEventProp(key),
172
+ detail,
173
+ bubbles: true,
174
+ composed: true,
175
+ cancelable: false
176
+ };
177
+ }
178
+ function extractEventDefinition(key, node) {
179
+ var _extractEventDetailTy;
180
+ const result = createComponentEvent(key);
181
+ if (!t.isCallExpression(node)) return result;
182
+ if (!t.isIdentifier(node.callee, { name: "event" })) return result;
183
+ result.detail = (_extractEventDetailTy = extractEventDetailType(node)) !== null && _extractEventDetailTy !== void 0 ? _extractEventDetailTy : result.detail;
184
+ const first = node.arguments[0];
185
+ if (t.isStringLiteral(first)) {
186
+ result.name = first.value;
187
+ return result;
188
+ }
189
+ if (t.isObjectExpression(first)) {
190
+ const name = getObjectProperty(first, "name");
191
+ const bubbles = getObjectProperty(first, "bubbles");
192
+ const composed = getObjectProperty(first, "composed");
193
+ const cancelable = getObjectProperty(first, "cancelable");
194
+ const nameValue = staticValue(name);
195
+ const bubblesValue = staticValue(bubbles);
196
+ const composedValue = staticValue(composed);
197
+ const cancelableValue = staticValue(cancelable);
198
+ if (typeof nameValue === "string") result.name = nameValue;
199
+ if (typeof bubblesValue === "boolean") result.bubbles = bubblesValue;
200
+ if (typeof composedValue === "boolean") result.composed = composedValue;
201
+ if (typeof cancelableValue === "boolean") result.cancelable = cancelableValue;
202
+ }
203
+ return result;
204
+ }
205
+ function extractEventDetailType(node) {
206
+ var _node$typeParameters;
207
+ const first = (_node$typeParameters = node.typeParameters) === null || _node$typeParameters === void 0 ? void 0 : _node$typeParameters.params[0];
208
+ if (!t.isTSTypeLiteral(first)) return void 0;
209
+ const detail = {};
210
+ for (const member of first.members) {
211
+ var _member$typeAnnotatio;
212
+ if (!t.isTSPropertySignature(member)) continue;
213
+ const key = getObjectKey(member.key);
214
+ if (!key) continue;
215
+ detail[key] = inferTsType((_member$typeAnnotatio = member.typeAnnotation) === null || _member$typeAnnotatio === void 0 ? void 0 : _member$typeAnnotatio.typeAnnotation);
216
+ }
217
+ return Object.keys(detail).length > 0 ? detail : void 0;
218
+ }
219
+ function inferTsType(node) {
220
+ if (!node) return "unknown";
221
+ if (t.isTSStringKeyword(node)) return "string";
222
+ if (t.isTSNumberKeyword(node)) return "number";
223
+ if (t.isTSBooleanKeyword(node)) return "boolean";
224
+ if (t.isTSObjectKeyword(node) || t.isTSTypeLiteral(node)) return "object";
225
+ if (t.isTSArrayType(node) || t.isTSTupleType(node)) return "array";
226
+ if (t.isTSFunctionType(node)) return "function";
227
+ if (t.isTSTypeReference(node)) return inferTsTypeReference(node);
228
+ return "unknown";
229
+ }
230
+ function inferTsTypeReference(node) {
231
+ const name = t.isIdentifier(node.typeName) ? node.typeName.name : void 0;
232
+ switch (name) {
233
+ case "String": return "string";
234
+ case "Number": return "number";
235
+ case "Boolean": return "boolean";
236
+ case "Array":
237
+ case "ReadonlyArray": return "array";
238
+ case "Function": return "function";
239
+ case "Record": return "object";
240
+ default: return name !== null && name !== void 0 ? name : "unknown";
241
+ }
242
+ }
243
+ function toKebabCase$1(value) {
244
+ return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
245
+ }
246
+ function toReactEventProp(value) {
247
+ return `on${value.split("-").filter(Boolean).map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join("")}`;
248
+ }
249
+ //#endregion
154
250
  //#region packages/web-c/component-analyzer/src/extractMeta.ts
155
251
  function extractInlineMeta(options) {
156
252
  if (!options) return {};
157
253
  const metaNode = getObjectProperty(options, "meta");
158
- if (!t.isObjectExpression(metaNode)) return {};
159
- const value = staticValue(metaNode);
160
- if (!value || typeof value !== "object" || Array.isArray(value)) return {};
161
- return value;
254
+ const result = {};
255
+ if (t.isObjectExpression(metaNode)) {
256
+ const value = staticValue(metaNode);
257
+ if (value && typeof value === "object" && !Array.isArray(value)) Object.assign(result, value);
258
+ }
259
+ assignTopLevelStaticValue(options, result, "slots");
260
+ assignTopLevelStaticValue(options, result, "parts");
261
+ assignTopLevelStaticValue(options, result, "cssVars");
262
+ assignTopLevelStaticValue(options, result, "methods");
263
+ assignTopLevelStaticValue(options, result, "models");
264
+ return result;
265
+ }
266
+ function assignTopLevelStaticValue(options, result, key) {
267
+ const node = getObjectProperty(options, key);
268
+ if (!node) return;
269
+ const value = staticValue(node);
270
+ if (key === "parts") {
271
+ result.cssParts = Array.isArray(value) ? value.filter((item) => typeof item === "string") : result.cssParts;
272
+ return;
273
+ }
274
+ result[key] = value;
162
275
  }
163
276
  //#endregion
164
277
  //#region packages/web-c/component-analyzer/src/extractProps.ts
165
- function extractShadowOption(options) {
278
+ function extractComponentOptions(options) {
166
279
  if (!options) return {};
280
+ const result = {};
167
281
  const shadowNode = getObjectProperty(options, "shadow");
168
- if (!shadowNode) return {};
169
- const value = staticValue(shadowNode);
170
- if (typeof value !== "boolean") return {};
171
- return { shadow: value };
282
+ if (shadowNode) {
283
+ const value = staticValue(shadowNode);
284
+ if (typeof value === "boolean") result.shadow = value;
285
+ }
286
+ const formAssociatedNode = getObjectProperty(options, "formAssociated");
287
+ if (formAssociatedNode) {
288
+ const value = staticValue(formAssociatedNode);
289
+ if (typeof value === "boolean") result.formAssociated = value;
290
+ }
291
+ return result;
172
292
  }
173
293
  function extractRuntimeProps(options) {
174
294
  if (!options) return {};
@@ -208,11 +328,15 @@ function validateRuntimePropsDefinition(options, optionsArgument) {
208
328
  continue;
209
329
  }
210
330
  if (t.isIdentifier(member.value)) {
211
- if (!isPropConstructorName(member.value.name)) messages.push(`Prop "${propName}" must use String, Number, Boolean, Object, Array, or an inline prop options object.`);
331
+ if (!isPropConstructorName(member.value.name)) messages.push(`Prop "${propName}" must use String, Number, Boolean, Object, Array, Function, prop(values), prop(Constructor), or an inline prop options object.`);
332
+ continue;
333
+ }
334
+ if (isPropCall(member.value)) {
335
+ validatePropCall(propName, member.value, messages);
212
336
  continue;
213
337
  }
214
338
  if (!t.isObjectExpression(member.value)) {
215
- messages.push(`Prop "${propName}" must use an inline prop options object.`);
339
+ messages.push(`Prop "${propName}" must use an inline prop options object, prop(values), or prop(Constructor).`);
216
340
  continue;
217
341
  }
218
342
  validatePropOptions(propName, member.value, messages);
@@ -231,7 +355,7 @@ function validatePropOptions(propName, options, messages) {
231
355
  continue;
232
356
  }
233
357
  if (optionName === "type") {
234
- if (!t.isIdentifier(member.value) || !isPropConstructorName(member.value.name)) messages.push(`Prop "${propName}" type must be String, Number, Boolean, Object, or Array.`);
358
+ if (!t.isIdentifier(member.value) || !isPropConstructorName(member.value.name)) messages.push(`Prop "${propName}" type must be String, Number, Boolean, Object, Array, or Function.`);
235
359
  continue;
236
360
  }
237
361
  if (optionName === "attr") {
@@ -250,16 +374,27 @@ function validatePropOptions(propName, options, messages) {
250
374
  continue;
251
375
  }
252
376
  if (value !== void 0 && typeof value !== "boolean") messages.push(`Prop "${propName}" reflect must be a static boolean.`);
377
+ continue;
378
+ }
379
+ if (optionName === "values") {
380
+ if (!isStaticStringArray(member.value)) messages.push(`Prop "${propName}" values must be a static string array.`);
381
+ continue;
382
+ }
383
+ if (optionName === "serialize" || optionName === "deserialize") {
384
+ if (!isFunctionLikeReference(member.value)) messages.push(`Prop "${propName}" ${optionName} must be a function.`);
253
385
  }
254
386
  }
255
387
  }
256
388
  function extractRuntimeProp(node) {
257
389
  if (t.isIdentifier(node)) return { type: typeFromConstructorName(node.name) };
390
+ if (isPropCall(node)) return extractPropCall(node);
258
391
  if (t.isObjectExpression(node)) {
259
392
  const typeNode = getObjectProperty(node, "type");
260
393
  const attrNode = getObjectProperty(node, "attr");
261
394
  const reflectNode = getObjectProperty(node, "reflect");
262
395
  const defaultNode = getObjectProperty(node, "default");
396
+ const serializeNode = getObjectProperty(node, "serialize");
397
+ const deserializeNode = getObjectProperty(node, "deserialize");
263
398
  const prop = { type: t.isIdentifier(typeNode) ? typeFromConstructorName(typeNode.name) : "unknown" };
264
399
  if (attrNode) {
265
400
  const attr = staticValue(attrNode);
@@ -272,16 +407,68 @@ function extractRuntimeProp(node) {
272
407
  if (defaultNode) {
273
408
  if (!t.isFunctionExpression(defaultNode) && !t.isArrowFunctionExpression(defaultNode)) prop.default = staticValue(defaultNode);
274
409
  }
410
+ if (serializeNode) prop.serialize = true;
411
+ if (deserializeNode) prop.deserialize = true;
412
+ const values = extractStaticStringArray(getObjectProperty(node, "values"));
413
+ if (values) prop.values = values;
275
414
  return prop;
276
415
  }
277
416
  return { type: "unknown" };
278
417
  }
418
+ function isPropCall(node) {
419
+ return t.isCallExpression(node) && t.isIdentifier(node.callee, { name: "prop" });
420
+ }
421
+ function validatePropCall(propName, node, messages) {
422
+ if (!isStaticStringArray(node.arguments[0]) && !isPropConstructorArgument(node.arguments[0])) messages.push(`Prop "${propName}" prop() first argument must be a static string array or prop constructor.`);
423
+ const optionsNode = node.arguments[1];
424
+ if (optionsNode && !t.isObjectExpression(optionsNode)) {
425
+ messages.push(`Prop "${propName}" prop() options must be an inline object literal.`);
426
+ return;
427
+ }
428
+ if (t.isObjectExpression(optionsNode)) validatePropOptions(propName, optionsNode, messages);
429
+ }
430
+ function extractPropCall(node) {
431
+ var _extractStaticStringA;
432
+ const inputNode = node.arguments[0];
433
+ const optionsNode = node.arguments[1];
434
+ const prop = t.isObjectExpression(optionsNode) ? extractRuntimeProp(optionsNode) : { type: "string" };
435
+ if (isPropConstructorArgument(inputNode)) {
436
+ prop.type = typeFromConstructorName(inputNode.name);
437
+ if (inputNode.name === "Boolean") {
438
+ var _prop$default, _prop$reflect;
439
+ (_prop$default = prop.default) !== null && _prop$default !== void 0 || (prop.default = false);
440
+ (_prop$reflect = prop.reflect) !== null && _prop$reflect !== void 0 || (prop.reflect = true);
441
+ }
442
+ return prop;
443
+ }
444
+ prop.type = "string";
445
+ prop.values = (_extractStaticStringA = extractStaticStringArray(node.arguments[0])) !== null && _extractStaticStringA !== void 0 ? _extractStaticStringA : [];
446
+ return prop;
447
+ }
448
+ function isPropConstructorArgument(node) {
449
+ return t.isIdentifier(node) && isPropConstructorName(node.name);
450
+ }
451
+ function isStaticStringArray(node) {
452
+ return Boolean(extractStaticStringArray(node));
453
+ }
454
+ function extractStaticStringArray(node) {
455
+ if (!t.isArrayExpression(node)) return void 0;
456
+ const values = [];
457
+ for (const item of node.elements) {
458
+ if (!t.isStringLiteral(item)) return void 0;
459
+ values.push(item.value);
460
+ }
461
+ return values;
462
+ }
279
463
  function isPropConstructorName(name) {
280
- return name === "String" || name === "Number" || name === "Boolean" || name === "Object" || name === "Array";
464
+ return name === "String" || name === "Number" || name === "Boolean" || name === "Object" || name === "Array" || name === "Function";
281
465
  }
282
466
  function isExplicitUndefined(node) {
283
467
  return t.isIdentifier(node) && node.name === "undefined";
284
468
  }
469
+ function isFunctionLikeReference(node) {
470
+ return t.isFunctionExpression(node) || t.isArrowFunctionExpression(node) || t.isIdentifier(node);
471
+ }
285
472
  function typeFromConstructorName(name) {
286
473
  switch (name) {
287
474
  case "String": return "string";
@@ -289,6 +476,7 @@ function typeFromConstructorName(name) {
289
476
  case "Boolean": return "boolean";
290
477
  case "Object": return "object";
291
478
  case "Array": return "array";
479
+ case "Function": return "function";
292
480
  default: return "unknown";
293
481
  }
294
482
  }
@@ -296,23 +484,27 @@ function typeFromConstructorName(name) {
296
484
  //#region packages/web-c/component-analyzer/src/extractSetup.ts
297
485
  function extractSetupMeta(setup) {
298
486
  const events = {};
487
+ const methods = {};
299
488
  const slots = {};
300
489
  const hostAttributes = [];
301
490
  const cssParts = [];
302
491
  if (!setup || t.isSpreadElement(setup) || t.isArgumentPlaceholder(setup)) return {
303
492
  events,
493
+ methods,
304
494
  slots,
305
495
  hostAttributes,
306
496
  cssParts
307
497
  };
308
498
  walk(setup, (node) => {
309
499
  extractEmit(node, events);
500
+ extractExpose(node, methods);
310
501
  extractSlot(node, slots);
311
502
  extractHostAttributes(node, hostAttributes);
312
503
  extractCssParts(node, cssParts);
313
504
  });
314
505
  return {
315
506
  events,
507
+ methods,
316
508
  slots,
317
509
  hostAttributes: uniqueSorted(hostAttributes),
318
510
  cssParts: uniqueSorted(cssParts)
@@ -320,13 +512,21 @@ function extractSetupMeta(setup) {
320
512
  }
321
513
  function extractEmit(node, events) {
322
514
  if (!t.isCallExpression(node)) return;
323
- if (!t.isIdentifier(node.callee, { name: "emit" })) return;
324
- const first = node.arguments[0];
325
- if (!t.isStringLiteral(first)) return;
326
- const eventName = first.value;
327
- events[eventName] || (events[eventName] = {});
328
- const detailNode = node.arguments[1];
329
- if (t.isObjectExpression(detailNode)) events[eventName].detail = inferDetail(detailNode);
515
+ const emitKey = getEmitKey(node.callee);
516
+ if (!emitKey) return;
517
+ events[emitKey] || (events[emitKey] = createComponentEvent(emitKey));
518
+ const detailNode = node.arguments[0];
519
+ if (t.isObjectExpression(detailNode)) events[emitKey].detail = inferDetail(detailNode);
520
+ }
521
+ function getEmitKey(callee) {
522
+ if (t.isMemberExpression(callee)) {
523
+ if (t.isIdentifier(callee.object, { name: "emit" }) && !callee.computed) return getMemberPropertyName(callee.property);
524
+ if (t.isMemberExpression(callee.object) && t.isIdentifier(callee.object.property, { name: "emit" }) && !callee.computed) return getMemberPropertyName(callee.property);
525
+ }
526
+ }
527
+ function getMemberPropertyName(property) {
528
+ if (t.isIdentifier(property)) return property.name;
529
+ if (t.isStringLiteral(property)) return property.value;
330
530
  }
331
531
  function inferDetail(node) {
332
532
  const result = {};
@@ -351,9 +551,111 @@ function extractSlot(node, slots) {
351
551
  var _getJSXStringAttribut;
352
552
  if (!t.isJSXElement(node)) return;
353
553
  const name = node.openingElement.name;
354
- if (!t.isJSXIdentifier(name, { name: "Slot" })) return;
554
+ if (!t.isJSXIdentifier(name, { name: "Slot" }) && !t.isJSXIdentifier(name, { name: "slot" })) return;
355
555
  const slotName = (_getJSXStringAttribut = getJSXStringAttribute(node, "name")) !== null && _getJSXStringAttribut !== void 0 ? _getJSXStringAttribut : "default";
356
- slots[slotName] || (slots[slotName] = {});
556
+ slots[slotName] || (slots[slotName] = { name: slotName });
557
+ }
558
+ function extractExpose(node, methods) {
559
+ if (!t.isCallExpression(node)) return;
560
+ if (!isExposeCallee(node.callee)) return;
561
+ const first = node.arguments[0];
562
+ if (!t.isObjectExpression(first)) return;
563
+ for (const member of first.properties) {
564
+ if (!t.isObjectMethod(member) && !t.isObjectProperty(member)) continue;
565
+ const name = getObjectKey(member.key);
566
+ if (!name) continue;
567
+ methods[name] = extractMethod(member, name);
568
+ }
569
+ }
570
+ function extractMethod(member, name) {
571
+ var _unwrapPromiseType, _formatTsType;
572
+ const fn = t.isObjectMethod(member) ? member : t.isFunctionExpression(member.value) || t.isArrowFunctionExpression(member.value) ? member.value : void 0;
573
+ if (!fn) return { name };
574
+ const returnType = t.isTSTypeAnnotation(fn.returnType) ? fn.returnType.typeAnnotation : void 0;
575
+ const normalizedReturn = fn.async ? (_unwrapPromiseType = unwrapPromiseType(returnType)) !== null && _unwrapPromiseType !== void 0 ? _unwrapPromiseType : returnType : returnType;
576
+ return {
577
+ name,
578
+ parameters: fn.params.map((param, index) => extractMethodParameter(param, index)),
579
+ returns: (_formatTsType = formatTsType(normalizedReturn)) !== null && _formatTsType !== void 0 ? _formatTsType : "unknown",
580
+ async: fn.async
581
+ };
582
+ }
583
+ function extractMethodParameter(param, index) {
584
+ var _formatTsType4;
585
+ if (t.isTSParameterProperty(param)) return extractMethodParameter(param.parameter, index);
586
+ if (t.isAssignmentPattern(param)) {
587
+ var _formatTsType2;
588
+ return {
589
+ name: t.isIdentifier(param.left) ? param.left.name : `arg${index}`,
590
+ type: (_formatTsType2 = formatTsType(getPatternTypeAnnotation(param.left))) !== null && _formatTsType2 !== void 0 ? _formatTsType2 : inferExpressionType(param.right),
591
+ optional: true
592
+ };
593
+ }
594
+ if (t.isRestElement(param)) {
595
+ var _ref, _formatTsType3;
596
+ return {
597
+ name: t.isIdentifier(param.argument) ? param.argument.name : `args${index}`,
598
+ type: (_ref = (_formatTsType3 = formatTsType(getPatternTypeAnnotation(param))) !== null && _formatTsType3 !== void 0 ? _formatTsType3 : formatTsType(getPatternTypeAnnotation(param.argument))) !== null && _ref !== void 0 ? _ref : "unknown[]",
599
+ optional: false,
600
+ rest: true
601
+ };
602
+ }
603
+ return {
604
+ name: t.isIdentifier(param) ? param.name : `arg${index}`,
605
+ type: (_formatTsType4 = formatTsType(getPatternTypeAnnotation(param))) !== null && _formatTsType4 !== void 0 ? _formatTsType4 : "unknown",
606
+ optional: Boolean(t.isIdentifier(param) && param.optional)
607
+ };
608
+ }
609
+ function getPatternTypeAnnotation(node) {
610
+ if (t.isIdentifier(node) || t.isObjectPattern(node) || t.isArrayPattern(node) || t.isRestElement(node)) return t.isTSTypeAnnotation(node.typeAnnotation) ? node.typeAnnotation.typeAnnotation : void 0;
611
+ }
612
+ function unwrapPromiseType(node) {
613
+ if (t.isTSTypeReference(node) && t.isIdentifier(node.typeName, { name: "Promise" })) {
614
+ var _node$typeParameters;
615
+ return (_node$typeParameters = node.typeParameters) === null || _node$typeParameters === void 0 ? void 0 : _node$typeParameters.params[0];
616
+ }
617
+ }
618
+ function formatTsType(node) {
619
+ if (!node) return void 0;
620
+ if (t.isTSStringKeyword(node)) return "string";
621
+ if (t.isTSNumberKeyword(node)) return "number";
622
+ if (t.isTSBooleanKeyword(node)) return "boolean";
623
+ if (t.isTSVoidKeyword(node)) return "void";
624
+ if (t.isTSUnknownKeyword(node)) return "unknown";
625
+ if (t.isTSAnyKeyword(node)) return "any";
626
+ if (t.isTSNullKeyword(node)) return "null";
627
+ if (t.isTSArrayType(node)) {
628
+ var _formatTsType5;
629
+ return `${(_formatTsType5 = formatTsType(node.elementType)) !== null && _formatTsType5 !== void 0 ? _formatTsType5 : "unknown"}[]`;
630
+ }
631
+ if (t.isTSUnionType(node)) return node.types.map((type) => {
632
+ var _formatTsType6;
633
+ return (_formatTsType6 = formatTsType(type)) !== null && _formatTsType6 !== void 0 ? _formatTsType6 : "unknown";
634
+ }).join(" | ");
635
+ if (t.isTSLiteralType(node)) return staticLiteralType(node.literal);
636
+ if (t.isTSTypeReference(node)) {
637
+ var _node$typeParameters2;
638
+ const name = formatEntityName(node.typeName);
639
+ const params = (_node$typeParameters2 = node.typeParameters) === null || _node$typeParameters2 === void 0 ? void 0 : _node$typeParameters2.params;
640
+ return (params === null || params === void 0 ? void 0 : params.length) ? `${name}<${params.map((type) => {
641
+ var _formatTsType7;
642
+ return (_formatTsType7 = formatTsType(type)) !== null && _formatTsType7 !== void 0 ? _formatTsType7 : "unknown";
643
+ }).join(", ")}>` : name;
644
+ }
645
+ return "unknown";
646
+ }
647
+ function formatEntityName(name) {
648
+ return t.isIdentifier(name) ? name.name : `${formatEntityName(name.left)}.${name.right.name}`;
649
+ }
650
+ function staticLiteralType(node) {
651
+ if (t.isStringLiteral(node)) return JSON.stringify(node.value);
652
+ if (t.isNumericLiteral(node)) return String(node.value);
653
+ if (t.isBooleanLiteral(node)) return String(node.value);
654
+ return "unknown";
655
+ }
656
+ function isExposeCallee(callee) {
657
+ if (t.isIdentifier(callee, { name: "expose" })) return true;
658
+ return t.isMemberExpression(callee) && t.isIdentifier(callee.property, { name: "expose" });
357
659
  }
358
660
  function extractHostAttributes(node, hostAttributes) {
359
661
  if (!t.isJSXElement(node)) return;
@@ -528,12 +830,14 @@ function _objectSpread2(e) {
528
830
  //#endregion
529
831
  //#region packages/web-c/component-analyzer/src/merge.ts
530
832
  function buildComponentRecord(options) {
531
- const { file, call, runtimeProps, runtimePropsDiagnostics, typeProps, setupMeta, inlineMeta, shadow } = options;
833
+ const { file, call, runtimeProps, runtimePropsDiagnostics, emits: declaredEvents, typeProps, setupMeta, inlineMeta, shadow, formAssociated } = options;
532
834
  const props = mergeProps(runtimeProps, typeProps, inlineMeta.props);
533
- const events = mergeEvents(setupMeta.events, inlineMeta.events);
835
+ const events = mergeEvents(declaredEvents, setupMeta.events, inlineMeta.events);
836
+ const methods = mergeMethods(setupMeta.methods, inlineMeta.methods);
837
+ const models = inlineMeta.models === void 0 ? inferModels(props, events) : normalizeModels(inlineMeta.models);
534
838
  const slots = mergeSlots(setupMeta.slots, inlineMeta.slots);
535
839
  const cssParts = unique([...setupMeta.cssParts, ...toStringArray(inlineMeta.cssParts)]);
536
- const cssVars = unique(toStringArray(inlineMeta.cssVars));
840
+ const cssVars = toCssVarsRecord(inlineMeta.cssVars);
537
841
  const hostAttributes = unique(setupMeta.hostAttributes);
538
842
  const restMeta = stripKnownMetaFields(inlineMeta);
539
843
  return {
@@ -545,14 +849,51 @@ function buildComponentRecord(options) {
545
849
  runtimeProps,
546
850
  runtimePropsDiagnostics: (runtimePropsDiagnostics === null || runtimePropsDiagnostics === void 0 ? void 0 : runtimePropsDiagnostics.length) ? runtimePropsDiagnostics : void 0,
547
851
  events,
852
+ methods,
853
+ models,
548
854
  slots,
549
855
  hostAttributes,
550
856
  cssParts,
551
857
  cssVars,
552
858
  description: typeof inlineMeta.description === "string" ? inlineMeta.description : void 0,
553
- meta: shadow !== void 0 || restMeta ? _objectSpread2(_objectSpread2({}, restMeta), {}, { shadow }) : void 0
859
+ meta: shadow !== void 0 || formAssociated !== void 0 || restMeta ? _objectSpread2(_objectSpread2({}, restMeta), {}, {
860
+ shadow,
861
+ formAssociated
862
+ }) : void 0
554
863
  };
555
864
  }
865
+ function normalizeModels(value) {
866
+ if (!Array.isArray(value)) return void 0;
867
+ const models = [];
868
+ for (const item of value) {
869
+ if (!item || typeof item !== "object") continue;
870
+ const record = item;
871
+ if (typeof record.prop !== "string" || typeof record.event !== "string") continue;
872
+ models.push({
873
+ prop: record.prop,
874
+ event: record.event,
875
+ eventPath: typeof record.eventPath === "string" ? record.eventPath : void 0
876
+ });
877
+ }
878
+ return models.length ? models : void 0;
879
+ }
880
+ function inferModels(props, events) {
881
+ const models = [];
882
+ for (const prop of Object.keys(props)) {
883
+ var _event$name, _event$key;
884
+ const eventKey = `${prop}Change`;
885
+ const event = events[eventKey];
886
+ if (!(event === null || event === void 0 ? void 0 : event.detail) || !Object.prototype.hasOwnProperty.call(event.detail, prop)) continue;
887
+ const eventName = (_event$name = event.name) !== null && _event$name !== void 0 ? _event$name : toKebabCase((_event$key = event.key) !== null && _event$key !== void 0 ? _event$key : eventKey);
888
+ if (eventName !== `${toKebabCase(prop)}-change`) continue;
889
+ models.push({
890
+ prop,
891
+ event: eventName,
892
+ eventPath: `detail.${prop}`
893
+ });
894
+ }
895
+ return models.length ? models : void 0;
896
+ }
556
897
  function mergeProps(runtimeProps, typeProps, metaProps) {
557
898
  const names = unique([
558
899
  ...Object.keys(runtimeProps),
@@ -561,34 +902,101 @@ function mergeProps(runtimeProps, typeProps, metaProps) {
561
902
  ]);
562
903
  const result = {};
563
904
  for (const name of names) {
564
- var _typeProps$name, _runtimeProps$name, _metaProps$name, _ref, _rp$type, _tp$description, _rp$default, _rp$reflect, _rp$attr;
905
+ var _typeProps$name, _runtimeProps$name, _metaProps$name, _ref, _rp$type, _rp$values, _tp$description, _rp$default, _rp$reflect, _rp$attr, _rp$serialize, _rp$deserialize;
565
906
  const tp = (_typeProps$name = typeProps[name]) !== null && _typeProps$name !== void 0 ? _typeProps$name : {};
566
907
  const rp = (_runtimeProps$name = runtimeProps[name]) !== null && _runtimeProps$name !== void 0 ? _runtimeProps$name : {};
567
908
  const mp = (_metaProps$name = metaProps === null || metaProps === void 0 ? void 0 : metaProps[name]) !== null && _metaProps$name !== void 0 ? _metaProps$name : {};
568
909
  result[name] = {
569
910
  type: (_ref = (_rp$type = rp.type) !== null && _rp$type !== void 0 ? _rp$type : tp.type) !== null && _ref !== void 0 ? _ref : "unknown",
570
911
  required: tp.required,
571
- values: tp.values,
912
+ values: (_rp$values = rp.values) !== null && _rp$values !== void 0 ? _rp$values : tp.values,
572
913
  description: (_tp$description = tp.description) !== null && _tp$description !== void 0 ? _tp$description : mp.description,
573
914
  default: (_rp$default = rp.default) !== null && _rp$default !== void 0 ? _rp$default : mp.default,
574
915
  reflect: (_rp$reflect = rp.reflect) !== null && _rp$reflect !== void 0 ? _rp$reflect : mp.reflect,
575
- attr: (_rp$attr = rp.attr) !== null && _rp$attr !== void 0 ? _rp$attr : mp.attr
916
+ attr: (_rp$attr = rp.attr) !== null && _rp$attr !== void 0 ? _rp$attr : mp.attr,
917
+ serialize: (_rp$serialize = rp.serialize) !== null && _rp$serialize !== void 0 ? _rp$serialize : mp.serialize,
918
+ deserialize: (_rp$deserialize = rp.deserialize) !== null && _rp$deserialize !== void 0 ? _rp$deserialize : mp.deserialize
576
919
  };
577
920
  }
578
921
  return result;
579
922
  }
580
- function mergeEvents(inferred, explicit) {
581
- return _objectSpread2(_objectSpread2({}, inferred), explicit !== null && explicit !== void 0 ? explicit : {});
923
+ function mergeEvents(declared, inferred, explicit) {
924
+ const result = {};
925
+ for (const [key, value] of Object.entries(declared)) result[key] = mergeEvent(value, inferred[key]);
926
+ for (const [key, value] of Object.entries(explicit !== null && explicit !== void 0 ? explicit : {})) if (result[key]) result[key] = normalizeExplicitEvent(key, value, result[key]);
927
+ return result;
928
+ }
929
+ function mergeEvent(primary, fallback) {
930
+ var _primary$key, _primary$name, _primary$reactName, _primary$detail, _primary$bubbles, _primary$composed, _primary$cancelable, _primary$description;
931
+ return {
932
+ key: (_primary$key = primary.key) !== null && _primary$key !== void 0 ? _primary$key : fallback === null || fallback === void 0 ? void 0 : fallback.key,
933
+ name: (_primary$name = primary.name) !== null && _primary$name !== void 0 ? _primary$name : fallback === null || fallback === void 0 ? void 0 : fallback.name,
934
+ reactName: (_primary$reactName = primary.reactName) !== null && _primary$reactName !== void 0 ? _primary$reactName : fallback === null || fallback === void 0 ? void 0 : fallback.reactName,
935
+ detail: (_primary$detail = primary.detail) !== null && _primary$detail !== void 0 ? _primary$detail : fallback === null || fallback === void 0 ? void 0 : fallback.detail,
936
+ bubbles: (_primary$bubbles = primary.bubbles) !== null && _primary$bubbles !== void 0 ? _primary$bubbles : fallback === null || fallback === void 0 ? void 0 : fallback.bubbles,
937
+ composed: (_primary$composed = primary.composed) !== null && _primary$composed !== void 0 ? _primary$composed : fallback === null || fallback === void 0 ? void 0 : fallback.composed,
938
+ cancelable: (_primary$cancelable = primary.cancelable) !== null && _primary$cancelable !== void 0 ? _primary$cancelable : fallback === null || fallback === void 0 ? void 0 : fallback.cancelable,
939
+ description: (_primary$description = primary.description) !== null && _primary$description !== void 0 ? _primary$description : fallback === null || fallback === void 0 ? void 0 : fallback.description
940
+ };
941
+ }
942
+ function normalizeExplicitEvent(key, value, base) {
943
+ var _value$key, _value$name, _value$reactName, _value$detail, _value$bubbles, _value$composed, _value$cancelable, _value$description;
944
+ const fallback = base !== null && base !== void 0 ? base : createComponentEvent(key);
945
+ return {
946
+ key: (_value$key = value.key) !== null && _value$key !== void 0 ? _value$key : fallback.key,
947
+ name: (_value$name = value.name) !== null && _value$name !== void 0 ? _value$name : fallback.name,
948
+ reactName: (_value$reactName = value.reactName) !== null && _value$reactName !== void 0 ? _value$reactName : fallback.reactName,
949
+ detail: (_value$detail = value.detail) !== null && _value$detail !== void 0 ? _value$detail : fallback.detail,
950
+ bubbles: (_value$bubbles = value.bubbles) !== null && _value$bubbles !== void 0 ? _value$bubbles : fallback.bubbles,
951
+ composed: (_value$composed = value.composed) !== null && _value$composed !== void 0 ? _value$composed : fallback.composed,
952
+ cancelable: (_value$cancelable = value.cancelable) !== null && _value$cancelable !== void 0 ? _value$cancelable : fallback.cancelable,
953
+ description: (_value$description = value.description) !== null && _value$description !== void 0 ? _value$description : fallback.description
954
+ };
955
+ }
956
+ function mergeMethods(inferred, explicit) {
957
+ const result = _objectSpread2({}, inferred);
958
+ if (Array.isArray(explicit)) {
959
+ for (const name of explicit) if (typeof name === "string") result[name] = { name };
960
+ }
961
+ return result;
582
962
  }
583
963
  function mergeSlots(inferred, explicit) {
584
- return _objectSpread2(_objectSpread2({}, inferred), explicit !== null && explicit !== void 0 ? explicit : {});
964
+ if (Array.isArray(explicit)) {
965
+ const result = _objectSpread2({}, inferred);
966
+ for (const name of explicit) if (typeof name === "string") result[name] = { name };
967
+ return result;
968
+ }
969
+ if (!explicit || typeof explicit !== "object") return _objectSpread2({}, inferred);
970
+ return _objectSpread2(_objectSpread2({}, inferred), explicit);
585
971
  }
586
972
  function toStringArray(value) {
587
973
  return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
588
974
  }
975
+ function toCssVarsRecord(value) {
976
+ if (Array.isArray(value)) {
977
+ const result = {};
978
+ for (const item of value) if (typeof item === "string") result[item] = { name: item };
979
+ return result;
980
+ }
981
+ if (value && typeof value === "object") {
982
+ const result = {};
983
+ for (const [name, item] of Object.entries(value)) if (item && typeof item === "object") {
984
+ const description = item.description;
985
+ result[name] = {
986
+ name,
987
+ description: typeof description === "string" ? description : void 0
988
+ };
989
+ } else result[name] = { name };
990
+ return result;
991
+ }
992
+ return {};
993
+ }
589
994
  function unique(values) {
590
995
  return Array.from(new Set(values)).sort();
591
996
  }
997
+ function toKebabCase(value) {
998
+ return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
999
+ }
592
1000
  function stripKnownMetaFields(meta) {
593
1001
  const rest = _objectSpread2({}, meta);
594
1002
  delete rest.description;
@@ -598,6 +1006,9 @@ function stripKnownMetaFields(meta) {
598
1006
  delete rest.cssVars;
599
1007
  delete rest.cssParts;
600
1008
  delete rest.shadow;
1009
+ delete rest.formAssociated;
1010
+ delete rest.methods;
1011
+ delete rest.models;
601
1012
  return Object.keys(rest).length ? rest : void 0;
602
1013
  }
603
1014
  //#endregion
@@ -610,8 +1021,9 @@ function analyzeFile(options) {
610
1021
  const ast = parseSource(code, file);
611
1022
  const calls = extractDefineElementCalls(ast);
612
1023
  const localPropTypes = collectLocalPropTypes(ast);
1024
+ const localSetupBindings = collectLocalSetupBindings(ast);
613
1025
  for (const call of calls) {
614
- var _localPropTypes$get, _shadowOption$shadow;
1026
+ var _localPropTypes$get, _componentOptions$sha, _componentOptions$for;
615
1027
  const runtimePropsDiagnostics = validateRuntimePropsDefinition(call.options, call.call.arguments[1]);
616
1028
  for (const message of runtimePropsDiagnostics) diagnostics.push({
617
1029
  level: "warning",
@@ -619,24 +1031,27 @@ function analyzeFile(options) {
619
1031
  message: `<${call.tag}> ${message}`
620
1032
  });
621
1033
  const runtimeProps = extractRuntimeProps(call.options);
622
- const shadowOption = extractShadowOption(call.options);
1034
+ const emits = extractEmits(call.options);
1035
+ const componentOptions = extractComponentOptions(call.options);
623
1036
  const typeProps = call.propsTypeName ? (_localPropTypes$get = localPropTypes.get(call.propsTypeName)) !== null && _localPropTypes$get !== void 0 ? _localPropTypes$get : {} : {};
624
1037
  if (call.propsTypeName && !localPropTypes.has(call.propsTypeName) && !isGlobalUtilityType(call.propsTypeName)) diagnostics.push({
625
1038
  level: "warning",
626
1039
  file,
627
1040
  message: `Cannot resolve local props type "${call.propsTypeName}".`
628
1041
  });
629
- const setupMeta = extractSetupMeta(call.setup);
1042
+ const setupMeta = extractSetupMeta(resolveSetupBinding(call.setup, localSetupBindings));
630
1043
  const inlineMeta = extractInlineMeta(call.options);
631
1044
  components.push(buildComponentRecord({
632
1045
  file,
633
1046
  call,
634
1047
  runtimeProps,
635
1048
  runtimePropsDiagnostics,
1049
+ emits,
636
1050
  typeProps,
637
1051
  setupMeta,
638
1052
  inlineMeta,
639
- shadow: (_shadowOption$shadow = shadowOption.shadow) !== null && _shadowOption$shadow !== void 0 ? _shadowOption$shadow : typeof inlineMeta.shadow === "boolean" ? inlineMeta.shadow : void 0
1053
+ shadow: (_componentOptions$sha = componentOptions.shadow) !== null && _componentOptions$sha !== void 0 ? _componentOptions$sha : typeof inlineMeta.shadow === "boolean" ? inlineMeta.shadow : void 0,
1054
+ formAssociated: (_componentOptions$for = componentOptions.formAssociated) !== null && _componentOptions$for !== void 0 ? _componentOptions$for : typeof inlineMeta.formAssociated === "boolean" ? inlineMeta.formAssociated : void 0
640
1055
  }));
641
1056
  }
642
1057
  } catch (error) {
@@ -652,6 +1067,28 @@ function analyzeFile(options) {
652
1067
  diagnostics
653
1068
  };
654
1069
  }
1070
+ function collectLocalSetupBindings(ast) {
1071
+ const bindings = /* @__PURE__ */ new Map();
1072
+ for (const node of ast.program.body) {
1073
+ if (t.isFunctionDeclaration(node) && node.id) {
1074
+ bindings.set(node.id.name, node);
1075
+ continue;
1076
+ }
1077
+ if (!t.isVariableDeclaration(node)) continue;
1078
+ for (const declarator of node.declarations) {
1079
+ if (!t.isIdentifier(declarator.id) || !declarator.init) continue;
1080
+ if (t.isFunctionExpression(declarator.init) || t.isArrowFunctionExpression(declarator.init)) bindings.set(declarator.id.name, declarator.init);
1081
+ }
1082
+ }
1083
+ return bindings;
1084
+ }
1085
+ function resolveSetupBinding(setup, bindings) {
1086
+ if (t.isIdentifier(setup)) {
1087
+ var _bindings$get;
1088
+ return (_bindings$get = bindings.get(setup.name)) !== null && _bindings$get !== void 0 ? _bindings$get : setup;
1089
+ }
1090
+ return setup;
1091
+ }
655
1092
  function isGlobalUtilityType(name) {
656
1093
  return GLOBAL_UTILITY_TYPES.has(name);
657
1094
  }