@@ -18,6 +18,63 @@ export * from './types';
1818
1919const windowsPathReg = / \\ / g;
2020
21+ // Utility function to get the component node from an AST
22+ function getComponentNodeFromAst (
23+ ast : ts . SourceFile ,
24+ exportName : string ,
25+ ts : typeof import ( 'typescript' ) ,
26+ ) : ts . Node | undefined {
27+ let result : ts . Node | undefined ;
28+
29+ if ( exportName === 'default' ) {
30+ ast . forEachChild ( child => {
31+ if ( ts . isExportAssignment ( child ) ) {
32+ result = child . expression ;
33+ }
34+ } ) ;
35+ }
36+ else {
37+ ast . forEachChild ( child => {
38+ if (
39+ ts . isVariableStatement ( child )
40+ && child . modifiers ?. some ( mod => mod . kind === ts . SyntaxKind . ExportKeyword )
41+ ) {
42+ for ( const dec of child . declarationList . declarations ) {
43+ if ( dec . name . getText ( ast ) === exportName ) {
44+ result = dec . initializer ;
45+ }
46+ }
47+ }
48+ } ) ;
49+ }
50+
51+ return result ;
52+ }
53+
54+ // Utility function to get the component options node from a component node
55+ function getComponentOptionsNodeFromComponent (
56+ component : ts . Node | undefined ,
57+ ts : typeof import ( 'typescript' ) ,
58+ ) : ts . ObjectLiteralExpression | undefined {
59+ if ( component ) {
60+ // export default { ... }
61+ if ( ts . isObjectLiteralExpression ( component ) ) {
62+ return component ;
63+ }
64+ // export default defineComponent({ ... })
65+ else if ( ts . isCallExpression ( component ) ) {
66+ if ( component . arguments . length ) {
67+ const arg = component . arguments [ 0 ] ! ;
68+ if ( ts . isObjectLiteralExpression ( arg ) ) {
69+ return arg ;
70+ }
71+ }
72+ }
73+ }
74+
75+ return undefined ;
76+ }
77+
2178export function createCheckerByJsonConfigBase (
2279 ts : typeof import ( 'typescript' ) ,
2380 rootDir : string ,
@@ -282,8 +339,16 @@ interface ComponentMeta<T> {
282339 let _events : ReturnType < typeof getEvents > | undefined ;
283340 let _slots : ReturnType < typeof getSlots > | undefined ;
284341 let _exposed : ReturnType < typeof getExposed > | undefined ;
342+ let _name : string | undefined ;
343+ let _description : string | undefined ;
285344
286345 const meta = {
346+ get name ( ) {
347+ return _name ?? ( _name = getName ( ) ) ;
348+ } ,
349+ get description ( ) {
350+ return _description ?? ( _description = getDescription ( ) ) ;
351+ } ,
287352 get type ( ) {
288353 return _type ?? ( _type = getType ( ) ) ;
289354 } ,
@@ -450,6 +515,42 @@ interface ComponentMeta<T> {
450515
451516 return [ ] ;
452517 }
518+
519+ function getName ( ) {
520+ // Try to get name from component options
521+ const sourceScript = language . scripts . get ( componentPath ) ! ;
522+ const { snapshot } = sourceScript ;
523+ const vueFile = sourceScript . generated ?. root ;
524+
525+ if ( vueFile && exportName === 'default' && vueFile instanceof core . VueVirtualCode ) {
526+ // For Vue SFC, check the script section
527+ const { sfc } = vueFile ;
528+ if ( sfc . script ) {
529+ const name = readComponentName ( sfc . script . ast , exportName , ts ) ;
530+ if ( name ) {
531+ return name ;
532+ }
533+ }
534+ }
535+ else if ( ! vueFile ) {
536+ // For TS/JS files
537+ const ast = ts . createSourceFile (
538+ '/tmp.' + componentPath . slice ( componentPath . lastIndexOf ( '.' ) + 1 ) ,
539+ snapshot . getText ( 0 , snapshot . getLength ( ) ) ,
540+ ts . ScriptTarget . Latest ,
541+ ) ;
542+ return readComponentName ( ast , exportName , ts ) ;
543+ }
544+
545+ return undefined ;
546+ }
547+
548+ function getDescription ( ) {
549+ const sourceFile = program . getSourceFile ( componentPath ) ;
550+ if ( sourceFile ) {
551+ return readComponentDescription ( sourceFile , exportName , ts , typeChecker ) ;
552+ }
553+ }
453554 }
454555
455556 function _getExports (
@@ -877,51 +978,12 @@ function readTsComponentDefaultProps(
877978 return { } ;
878979
879980 function getComponentNode ( ) {
880- let result : ts . Node | undefined ;
881-
882- if ( exportName === 'default' ) {
883- ast . forEachChild ( child => {
884- if ( ts . isExportAssignment ( child ) ) {
885- result = child . expression ;
886- }
887- } ) ;
888- }
889- else {
890- ast . forEachChild ( child => {
891- if (
892- ts . isVariableStatement ( child )
893- && child . modifiers ?. some ( mod => mod . kind === ts . SyntaxKind . ExportKeyword )
894- ) {
895- for ( const dec of child . declarationList . declarations ) {
896- if ( dec . name . getText ( ast ) === exportName ) {
897- result = dec . initializer ;
898- }
899- }
900- }
901- } ) ;
902- }
903-
904- return result ;
981+ return getComponentNodeFromAst ( ast , exportName , ts ) ;
905982 }
906983
907984 function getComponentOptionsNode ( ) {
908985 const component = getComponentNode ( ) ;
909-
910- if ( component ) {
911- // export default { ... }
912- if ( ts . isObjectLiteralExpression ( component ) ) {
913- return component ;
914- }
915- // export default defineComponent({ ... })
916- else if ( ts . isCallExpression ( component ) ) {
917- if ( component . arguments . length ) {
918- const arg = component . arguments [ 0 ] ! ;
919- if ( ts . isObjectLiteralExpression ( arg ) ) {
920- return arg ;
921- }
922- }
923- }
924- }
986+ return getComponentOptionsNodeFromComponent ( component , ts ) ;
925987 }
926988
927989 function getPropsNode ( ) {
@@ -1011,3 +1073,84 @@ function resolveDefaultOptionExpression(
10111073 }
10121074 return _default ;
10131075}
1076+
1077+ function readComponentName (
1078+ ast : ts . SourceFile ,
1079+ exportName : string ,
1080+ ts : typeof import ( 'typescript' ) ,
1081+ ) : string | undefined {
1082+ const componentNode = getComponentNodeFromAst ( ast , exportName , ts ) ;
1083+ const optionsNode = getComponentOptionsNodeFromComponent ( componentNode , ts ) ;
1084+
1085+ if ( optionsNode ) {
1086+ const nameProp = optionsNode . properties . find (
1087+ prop => ts . isPropertyAssignment ( prop ) && prop . name ?. getText ( ast ) === 'name' ,
1088+ ) ;
1089+
1090+ if ( nameProp && ts . isPropertyAssignment ( nameProp ) && ts . isStringLiteral ( nameProp . initializer ) ) {
1091+ return nameProp . initializer . text ;
1092+ }
1093+ }
1094+
1095+ return undefined ;
1096+ }
1097+
1098+ function readComponentDescription (
1099+ ast : ts . SourceFile ,
1100+ exportName : string ,
1101+ ts : typeof import ( 'typescript' ) ,
1102+ typeChecker : ts . TypeChecker ,
1103+ ) : string | undefined {
1104+ const exportNode = getExportNode ( ) ;
1105+
1106+ if ( exportNode ) {
1107+ // Try to get JSDoc comments from the node using TypeScript API
1108+ const jsDocComments = ts . getJSDocCommentsAndTags ( exportNode ) ;
1109+ for ( const jsDoc of jsDocComments ) {
1110+ if ( ts . isJSDoc ( jsDoc ) && jsDoc . comment ) {
1111+ // Handle both string and array of comment parts
1112+ if ( typeof jsDoc . comment === 'string' ) {
1113+ return jsDoc . comment ;
1114+ }
1115+ else if ( Array . isArray ( jsDoc . comment ) ) {
1116+ return jsDoc . comment . map ( part => ( part as any ) . text || '' ) . join ( '' ) ;
1117+ }
1118+ }
1119+ }
1120+
1121+ // Fallback to symbol documentation
1122+ const symbol = typeChecker . getSymbolAtLocation ( exportNode ) ;
1123+ if ( symbol ) {
1124+ const description = ts . displayPartsToString ( symbol . getDocumentationComment ( typeChecker ) ) ;
1125+ return description || undefined ;
1126+ }
1127+ }
1128+
1129+ return undefined ;
1130+
1131+ function getExportNode ( ) {
1132+ let result : ts . Node | undefined ;
1133+
1134+ if ( exportName === 'default' ) {
1135+ ast . forEachChild ( child => {
1136+ if ( ts . isExportAssignment ( child ) ) {
1137+ // Return the export assignment itself, not the expression
1138+ result = child ;
1139+ }
1140+ } ) ;
1141+ }
1142+ else {
1143+ ast . forEachChild ( child => {
1144+ if (
1145+ ts . isVariableStatement ( child )
1146+ && child . modifiers ?. some ( mod => mod . kind === ts . SyntaxKind . ExportKeyword )
1147+ ) {
1148+ // Return the variable statement itself
1149+ result = child ;
1150+ }
1151+ } ) ;
1152+ }
1153+
1154+ return result ;
1155+ }
1156+ }
0 commit comments