@@ -110,7 +110,6 @@ function baseCreate(
110110 let fileNamesSet = new Set ( fileNames . map ( path => path . replace ( windowsPathReg , '/' ) ) ) ;
111111 let projectVersion = 0 ;
112112
113- const scriptRangesCache = new WeakMap < ts . SourceFile , core . ScriptRanges > ( ) ;
114113 const projectHost : TypeScriptProjectHost = {
115114 getCurrentDirectory : ( ) => rootPath ,
116115 getProjectVersion : ( ) => projectVersion . toString ( ) ,
@@ -206,35 +205,29 @@ function baseCreate(
206205 } ,
207206 } ;
208207
209- function getExportNames ( componentPath : string ) {
210- const program = tsLs . getProgram ( ) ! ;
211- const sourceFile = program . getSourceFile ( componentPath ) ;
212- if ( sourceFile ) {
213- const scriptRanges = getScriptRanges ( sourceFile ) ;
214- return Object . keys ( scriptRanges . exports ) ;
215- }
216- }
217-
218- function getComponentMeta ( componentPath : string , exportName = 'default' ) : ComponentMeta {
208+ function getProgramAndFile ( componentPath : string ) {
219209 let program = tsLs . getProgram ( ) ! ;
220210 let sourceFile = program . getSourceFile ( componentPath ) ;
221211 if ( ! sourceFile ) {
222212 fileNamesSet . add ( componentPath ) ;
223213 projectVersion ++ ;
224214 program = tsLs . getProgram ( ) ! ;
225- sourceFile = program . getSourceFile ( componentPath ) ;
226- if ( ! sourceFile ) {
227- throw `Could not find component file: ${ componentPath } ` ;
228- }
215+ sourceFile = program . getSourceFile ( componentPath ) ! ;
229216 }
217+ return [ program , sourceFile ] as const ;
218+ }
230219
231- const scriptRanges = getScriptRanges ( sourceFile ) ;
232- const component = scriptRanges . exports [ exportName ] ;
233- if ( ! component ) {
234- throw `Could not find export ${ exportName } ` ;
235- }
220+ function getExportNames ( componentPath : string ) {
221+ const [ program , sourceFile ] = getProgramAndFile ( componentPath ) ;
222+ return getExports ( program , sourceFile ) . map ( e => e . getName ( ) ) ;
223+ }
236224
237- const symbolNode = component . expression . node ;
225+ function getComponentMeta ( componentPath : string , exportName = 'default' ) : ComponentMeta {
226+ const [ program , sourceFile ] = getProgramAndFile ( componentPath ) ;
227+ const symbolNode = getExport ( ts , program , sourceFile , exportName ) ! ;
228+ if ( ! symbolNode ) {
229+ throw new Error ( `Export '${ exportName } ' not found in '${ componentPath } '.` ) ;
230+ }
238231 const typeChecker = program . getTypeChecker ( ) ;
239232
240233 let name : string | undefined ;
@@ -387,32 +380,55 @@ function baseCreate(
387380 }
388381
389382 function getName ( ) {
390- const sourceFile = program . getSourceFile ( componentPath ) ;
391- if ( sourceFile ) {
392- const scriptRanges = getScriptRanges ( sourceFile ) ;
393- const name = scriptRanges ?. exports [ exportName ] ?. options ?. name ;
394- if ( name && ts . isStringLiteral ( name . node ) ) {
395- return name . node . text ;
396- }
383+ let decl = getExport ( ts , program , sourceFile , exportName ) ;
384+ if ( ! decl ) {
385+ return ;
386+ }
387+
388+ // const __VLS_export = ...
389+ const text = sourceFile . text . slice ( decl . pos , decl . end ) ;
390+ if ( text . includes ( core . names . _export ) ) {
391+ ts . forEachChild ( sourceFile , child2 => {
392+ if ( ts . isVariableStatement ( child2 ) ) {
393+ for ( const { name, initializer } of child2 . declarationList . declarations ) {
394+ if ( name . getText ( ) === core . names . _export && initializer ) {
395+ decl = initializer ;
396+ }
397+ }
398+ }
399+ } ) ;
397400 }
401+
402+ return core . parseOptionsFromExtression ( ts , decl , sourceFile ) ?. name ?. node . text ;
398403 }
399404
400405 function getDescription ( ) {
401- const sourceFile = program . getSourceFile ( componentPath ) ;
402- if ( sourceFile ) {
403- const scriptRanges = getScriptRanges ( sourceFile ) ;
404- return readComponentDescription ( ts , scriptRanges , exportName , typeChecker ) ;
406+ const decl = getExport ( ts , program , sourceFile , exportName ) ;
407+ if ( ! decl ) {
408+ return ;
405409 }
406- }
407- }
408410
409- function getScriptRanges ( sourceFile : ts . SourceFile ) {
410- let scriptRanges = scriptRangesCache . get ( sourceFile ) ;
411- if ( ! scriptRanges ) {
412- scriptRanges = core . parseScriptRanges ( ts , sourceFile , vueOptions ) ;
413- scriptRangesCache . set ( sourceFile , scriptRanges ) ;
411+ // Try to get JSDoc comments from the node using TypeScript API
412+ const jsDocComments = ts . getJSDocCommentsAndTags ( decl ) ;
413+ for ( const jsDoc of jsDocComments ) {
414+ if ( ts . isJSDoc ( jsDoc ) && jsDoc . comment ) {
415+ // Handle both string and array of comment parts
416+ if ( typeof jsDoc . comment === 'string' ) {
417+ return jsDoc . comment ;
418+ }
419+ else if ( Array . isArray ( jsDoc . comment ) ) {
420+ return jsDoc . comment . map ( part => ( part as any ) . text || '' ) . join ( '' ) ;
421+ }
422+ }
423+ }
424+
425+ // Fallback to symbol documentation
426+ const symbol = typeChecker . getSymbolAtLocation ( decl ) ;
427+ if ( symbol ) {
428+ const description = ts . displayPartsToString ( symbol . getDocumentationComment ( typeChecker ) ) ;
429+ return description || undefined ;
430+ }
414431 }
415- return scriptRanges ;
416432 }
417433
418434 function getVirtualCode ( fileName : string ) {
@@ -867,34 +883,27 @@ function resolveDefaultOptionExpression(
867883 return _default ;
868884}
869885
870- function readComponentDescription (
886+ function getExport (
871887 ts : typeof import ( 'typescript' ) ,
872- scriptRanges : core . ScriptRanges ,
888+ program : ts . Program ,
889+ sourceFile : ts . SourceFile ,
873890 exportName : string ,
874- typeChecker : ts . TypeChecker ,
875- ) : string | undefined {
876- const _export = scriptRanges . exports [ exportName ] ;
877-
878- if ( _export ) {
879- // Try to get JSDoc comments from the node using TypeScript API
880- const jsDocComments = ts . getJSDocCommentsAndTags ( _export . node ) ;
881- for ( const jsDoc of jsDocComments ) {
882- if ( ts . isJSDoc ( jsDoc ) && jsDoc . comment ) {
883- // Handle both string and array of comment parts
884- if ( typeof jsDoc . comment === 'string' ) {
885- return jsDoc . comment ;
886- }
887- else if ( Array . isArray ( jsDoc . comment ) ) {
888- return jsDoc . comment . map ( part => ( part as any ) . text || '' ) . join ( '' ) ;
889- }
890- }
891+ ) {
892+ const exports = getExports ( program , sourceFile ) ;
893+ const symbol = exports . find ( e => e . getName ( ) === exportName ) ;
894+ if ( symbol ?. valueDeclaration ) {
895+ const decl = symbol . valueDeclaration ;
896+ if ( ts . isExportAssignment ( decl ) ) {
897+ return decl . expression ;
891898 }
892-
893- // Fallback to symbol documentation
894- const symbol = typeChecker . getSymbolAtLocation ( _export . node ) ;
895- if ( symbol ) {
896- const description = ts . displayPartsToString ( symbol . getDocumentationComment ( typeChecker ) ) ;
897- return description || undefined ;
899+ if ( ts . isVariableDeclaration ( decl ) ) {
900+ return decl . initializer ;
898901 }
899902 }
900903}
904+
905+ function getExports ( program : ts . Program , sourceFile : ts . SourceFile ) {
906+ const typeChecker = program . getTypeChecker ( ) ;
907+ const moduleSymbol = typeChecker . getSymbolAtLocation ( sourceFile ) ;
908+ return moduleSymbol ? typeChecker . getExportsOfModule ( moduleSymbol ) : [ ] ;
909+ }
0 commit comments