11import type * as ts from 'typescript' ;
2+ import { names } from '../..' ;
23import type { TextRange , VueCompilerOptions } from '../types' ;
34import { getNodeText , getStartEnd } from '../utils/shared' ;
45import { getClosestMultiLineCommentRange , parseBindingRanges } from './utils' ;
@@ -7,108 +8,153 @@ export interface ScriptRanges extends ReturnType<typeof parseScriptRanges> {}
78
89export function parseScriptRanges (
910 ts : typeof import ( 'typescript' ) ,
10- ast : ts . SourceFile ,
11+ sourceFile : ts . SourceFile ,
1112 vueCompilerOptions : VueCompilerOptions ,
1213) {
13- let exportDefault :
14- | TextRange & {
14+ const _exports : Record <
15+ 'default' | string ,
16+ TextRange & {
1517 expression : TextRange ;
1618 isObjectLiteral : boolean ;
17- }
18- | undefined ;
19- let componentOptions :
20- | {
21- isObjectLiteral : boolean ;
22- expression : TextRange ;
23- args : TextRange ;
24- argsNode : ts . ObjectLiteralExpression ;
25- components : TextRange | undefined ;
26- componentsNode : ts . ObjectLiteralExpression | undefined ;
27- directives : TextRange | undefined ;
28- name : TextRange | undefined ;
29- inheritAttrs : string | undefined ;
30- }
31- | undefined ;
19+ options ?: {
20+ isObjectLiteral : boolean ;
21+ expression : TextRange ;
22+ args : TextRange < ts . ObjectLiteralExpression > ;
23+ components : TextRange < ts . ObjectLiteralExpression > | undefined ;
24+ directives : TextRange | undefined ;
25+ name : TextRange | undefined ;
26+ inheritAttrs : string | undefined ;
27+ } ;
28+ } | undefined
29+ > = { } ;
3230
33- const { bindings, components } = parseBindingRanges ( ts , ast , vueCompilerOptions . extensions ) ;
31+ const { bindings, components } = parseBindingRanges ( ts , sourceFile , vueCompilerOptions . extensions ) ;
3432
35- ts . forEachChild ( ast , raw => {
36- if ( ts . isExportAssignment ( raw ) ) {
37- exportDefault = {
38- ..._getStartEnd ( raw ) ,
39- expression : _getStartEnd ( raw . expression ) ,
40- isObjectLiteral : ts . isObjectLiteralExpression ( raw . expression ) ,
33+ ts . forEachChild ( sourceFile , child => {
34+ // export default ...
35+ if ( ts . isExportAssignment ( child ) ) {
36+ _exports . default = {
37+ ..._getStartEnd ( child ) ,
38+ expression : _getStartEnd ( child . expression ) ,
39+ isObjectLiteral : ts . isObjectLiteralExpression ( child . expression ) ,
40+ options : getOptions ( child . expression ) ,
4141 } ;
42- const comment = getClosestMultiLineCommentRange ( ts , raw , [ ] , ast ) ;
42+ const comment = getClosestMultiLineCommentRange ( ts , child , [ ] , sourceFile ) ;
4343 if ( comment ) {
44- exportDefault . start = comment . start ;
44+ _exports . default . start = comment . start ;
4545 }
4646
47- let node : ts . AsExpression | ts . ExportAssignment | ts . ParenthesizedExpression = raw ;
48- while ( isAsExpression ( node . expression ) || ts . isParenthesizedExpression ( node . expression ) ) { // fix https://github.com/vuejs/language-tools/issues/1882
49- node = node . expression ;
50- }
51-
52- let obj : ts . ObjectLiteralExpression | undefined ;
53- if ( ts . isObjectLiteralExpression ( node . expression ) ) {
54- obj = node . expression ;
55- }
56- else if ( ts . isCallExpression ( node . expression ) && node . expression . arguments . length ) {
57- const arg0 = node . expression . arguments [ 0 ] ! ;
58- if ( ts . isObjectLiteralExpression ( arg0 ) ) {
59- obj = arg0 ;
60- }
61- }
62- if ( obj ) {
63- let componentsOptionNode : ts . ObjectLiteralExpression | undefined ;
64- let directivesOptionNode : ts . ObjectLiteralExpression | undefined ;
65- let nameOptionNode : ts . Expression | undefined ;
66- let inheritAttrsOption : string | undefined ;
67- ts . forEachChild ( obj , node => {
68- if ( ts . isPropertyAssignment ( node ) && ts . isIdentifier ( node . name ) ) {
69- const name = _getNodeText ( node . name ) ;
70- if ( name === 'components' && ts . isObjectLiteralExpression ( node . initializer ) ) {
71- componentsOptionNode = node . initializer ;
72- }
73- else if ( name === 'directives' && ts . isObjectLiteralExpression ( node . initializer ) ) {
74- directivesOptionNode = node . initializer ;
75- }
76- else if ( name === 'name' ) {
77- nameOptionNode = node . initializer ;
78- }
79- else if ( name === 'inheritAttrs' ) {
80- inheritAttrsOption = _getNodeText ( node . initializer ) ;
47+ // const __VLS_export = ...
48+ const expressionText = sourceFile . text . slice ( _exports . default . expression . start , _exports . default . expression . end ) ;
49+ if ( expressionText . includes ( names . _export ) ) {
50+ let exportExp : ts . Expression | undefined ;
51+ ts . forEachChild ( sourceFile , child2 => {
52+ if ( ts . isVariableStatement ( child2 ) ) {
53+ for ( const decl of child2 . declarationList . declarations ) {
54+ if ( ! ts . isIdentifier ( decl . name ) ) {
55+ continue ;
56+ }
57+ if ( getNodeText ( ts , decl . name , sourceFile ) === names . _export && decl . initializer ) {
58+ exportExp = decl . initializer ;
59+ }
8160 }
8261 }
8362 } ) ;
84- componentOptions = {
85- isObjectLiteral : ts . isObjectLiteralExpression ( node . expression ) ,
86- expression : _getStartEnd ( node . expression ) ,
87- args : _getStartEnd ( obj ) ,
88- argsNode : obj ,
89- components : componentsOptionNode ? _getStartEnd ( componentsOptionNode ) : undefined ,
90- componentsNode : componentsOptionNode ,
91- directives : directivesOptionNode ? _getStartEnd ( directivesOptionNode ) : undefined ,
92- name : nameOptionNode ? _getStartEnd ( nameOptionNode ) : undefined ,
93- inheritAttrs : inheritAttrsOption ,
63+ if ( exportExp ) {
64+ _exports . default . expression = _getStartEnd ( exportExp ) ;
65+ _exports . default . isObjectLiteral = ts . isObjectLiteralExpression ( exportExp ) ;
66+ _exports . default . options = getOptions ( exportExp ) ;
67+ }
68+ }
69+ }
70+
71+ // export const Foo = ...
72+ if ( ts . isVariableStatement ( child ) && child . modifiers ?. some ( m => m . kind === ts . SyntaxKind . ExportKeyword ) ) {
73+ for ( const decl of child . declarationList . declarations ) {
74+ if ( ! ts . isIdentifier ( decl . name ) ) {
75+ continue ;
76+ }
77+ const exportVar = getNodeText ( ts , decl . name , sourceFile ) ;
78+ let node = decl . initializer ;
79+ if ( ! node ) {
80+ continue ;
81+ }
82+ _exports [ exportVar ] = {
83+ ..._getStartEnd ( decl ) ,
84+ expression : _getStartEnd ( node ) ,
85+ isObjectLiteral : ts . isObjectLiteralExpression ( node ) ,
86+ options : getOptions ( node ) ,
9487 } ;
9588 }
9689 }
9790 } ) ;
9891
9992 return {
100- exportDefault,
101- componentOptions,
93+ exports : _exports ,
10294 bindings,
10395 components,
10496 } ;
10597
106- function _getStartEnd ( node : ts . Node ) {
107- return getStartEnd ( ts , node , ast ) ;
98+ function getOptions ( exp : ts . Node ) {
99+ let obj : ts . ObjectLiteralExpression | undefined ;
100+
101+ while ( isAsExpression ( exp ) || ts . isParenthesizedExpression ( exp ) ) { // fix https://github.com/vuejs/language-tools/issues/1882
102+ exp = exp . expression ;
103+ }
104+
105+ if ( ts . isObjectLiteralExpression ( exp ) ) {
106+ obj = exp ;
107+ }
108+ else if ( ts . isCallExpression ( exp ) && exp . arguments . length ) {
109+ const arg0 = exp . arguments [ 0 ] ! ;
110+ if ( ts . isObjectLiteralExpression ( arg0 ) ) {
111+ obj = arg0 ;
112+ }
113+ }
114+
115+ if ( obj ) {
116+ let componentsOptionNode : ts . ObjectLiteralExpression | undefined ;
117+ let directivesOptionNode : ts . ObjectLiteralExpression | undefined ;
118+ let nameOptionNode : ts . Expression | undefined ;
119+ let inheritAttrsOption : string | undefined ;
120+ ts . forEachChild ( obj , node => {
121+ if ( ts . isPropertyAssignment ( node ) && ts . isIdentifier ( node . name ) ) {
122+ const name = _getNodeText ( node . name ) ;
123+ if ( name === 'components' && ts . isObjectLiteralExpression ( node . initializer ) ) {
124+ componentsOptionNode = node . initializer ;
125+ }
126+ else if ( name === 'directives' && ts . isObjectLiteralExpression ( node . initializer ) ) {
127+ directivesOptionNode = node . initializer ;
128+ }
129+ else if ( name === 'name' ) {
130+ nameOptionNode = node . initializer ;
131+ }
132+ else if ( name === 'inheritAttrs' ) {
133+ inheritAttrsOption = _getNodeText ( node . initializer ) ;
134+ }
135+ }
136+ } ) ;
137+ return {
138+ isObjectLiteral : ts . isObjectLiteralExpression ( exp ) ,
139+ expression : _getStartEnd ( exp ) ,
140+ args : _getStartEnd ( obj ) ,
141+ argsNode : obj ,
142+ components : componentsOptionNode ? _getStartEnd ( componentsOptionNode ) : undefined ,
143+ componentsNode : componentsOptionNode ,
144+ directives : directivesOptionNode ? _getStartEnd ( directivesOptionNode ) : undefined ,
145+ name : nameOptionNode ? _getStartEnd ( nameOptionNode ) : undefined ,
146+ nameNode : nameOptionNode ,
147+ inheritAttrs : inheritAttrsOption ,
148+ } ;
149+ }
150+ }
151+
152+ function _getStartEnd < T extends ts . Node > ( node : T ) : TextRange < T > {
153+ return getStartEnd ( ts , node , sourceFile ) ;
108154 }
109155
110156 function _getNodeText ( node : ts . Node ) {
111- return getNodeText ( ts , node , ast ) ;
157+ return getNodeText ( ts , node , sourceFile ) ;
112158 }
113159
114160 // isAsExpression is missing in tsc
0 commit comments