1
1
import { GetConfig } from '../types'
2
+ import { getFullTypeChecker } from '../utils'
2
3
3
- const reactTypesPath = 'node_modules/@types/react/index.d.ts '
4
+ const reactTypesPath = 'node_modules/@types/react/'
4
5
5
6
const symbolCache = new Map < string , boolean > ( )
6
7
@@ -53,24 +54,6 @@ export default (entries: ts.CompletionEntry[], node: ts.Node, position: number,
53
54
timings [ `${ name } Count` ] ??= 0
54
55
timings [ `${ name } Count` ] ++
55
56
}
56
- const getIsJsxComponentSignature = ( signature : ts . Signature ) => {
57
- let returnType : ts . Type | undefined = signature . getReturnType ( )
58
- if ( ! returnType ) return
59
- // todo setting to allow any!
60
- if ( returnType . flags & ts . TypeFlags . Any ) return false
61
- returnType = getPossiblyJsxType ( returnType )
62
- if ( ! returnType ) return false
63
- startMark ( )
64
- // todo(perf) this seems to be taking a lot of time (mui test 180ms)
65
- const typeString = typeChecker . typeToString ( returnType )
66
- addMark ( 'stringType' )
67
- // todo-low resolve indentifier instead
68
- // or compare node name from decl (invest perf)
69
- if ( [ 'Element' , 'ReactElement' ] . every ( s => ! typeString . startsWith ( s ) ) ) return
70
- const declFile = returnType . getSymbol ( ) ?. declarations ?. [ 0 ] ?. getSourceFile ( ) . fileName
71
- if ( ! declFile ?. endsWith ( reactTypesPath ) ) return
72
- return true
73
- }
74
57
const getIsEntryReactComponent = ( entry : ts . CompletionEntry ) => {
75
58
// todo add more checks from ref https://github.com/microsoft/TypeScript/blob/e4816ed44cf9bcfe7cebb997b1f44cdb5564dac4/src/compiler/checker.ts#L30030
76
59
// todo support classes
@@ -112,7 +95,7 @@ export default (entries: ts.CompletionEntry[], node: ts.Node, position: number,
112
95
// startMark()
113
96
const signatures = typeChecker . getSignaturesOfType ( entryType , ts . SignatureKind . Call )
114
97
// addMark('signatures')
115
- const result = signatures . length > 0 && signatures . every ( signature => getIsJsxComponentSignature ( signature ) )
98
+ const result = isJsxElement ( typeChecker , signatures , entryType )
116
99
if ( shouldBeCached ) symbolCache . set ( symbolSerialized , result )
117
100
return result
118
101
}
@@ -162,16 +145,30 @@ const isJsxOpeningElem = (position: number, node: ts.Node) => {
162
145
return false
163
146
}
164
147
165
- const getReactElementType = ( program : ts . Program ) => {
166
- const reactDeclSource = program . getSourceFiles ( ) . find ( name => name . fileName . endsWith ( reactTypesPath ) )
167
- const namespace = reactDeclSource && ts . forEachChild ( reactDeclSource , s => ts . isModuleDeclaration ( s ) && s . name . text === 'React' && s )
168
- if ( ! namespace || ! namespace . body ) return
169
- return ts . forEachChild ( namespace . body , node => {
170
- if ( ts . isInterfaceDeclaration ( node ) && node . name . text === 'ReactElement' ) {
171
- return node
172
- }
173
- return undefined
174
- } )
148
+ const isJsxElement = ( typeChecker : ts . TypeChecker , signatures : readonly ts . Signature [ ] , type : ts . Type ) => {
149
+ if ( signatures . length > 0 && signatures . every ( signature => getIsJsxComponentSignature ( typeChecker , signature ) ) ) return true
150
+ // allow pattern: const Component = condition ? 'div' : 'a'
151
+ if ( type . isUnion ( ) && type . types . every ( type => type . isStringLiteral ( ) ) ) return true
152
+ return false
153
+ }
154
+
155
+ const getIsJsxComponentSignature = ( typeChecker : ts . TypeChecker , signature : ts . Signature ) => {
156
+ let returnType : ts . Type | undefined = signature . getReturnType ( )
157
+ if ( ! returnType ) return
158
+ // todo setting to allow any
159
+ if ( returnType . flags & ts . TypeFlags . Any ) return false
160
+ returnType = getPossiblyJsxType ( returnType )
161
+ if ( ! returnType ) return false
162
+ // startMark()
163
+ // todo(perf) this seems to be taking a lot of time (mui test 180ms)
164
+ const typeString = typeChecker . typeToString ( returnType )
165
+ // addMark('stringType')
166
+ // todo-low resolve indentifier instead
167
+ // or compare node name from decl (invest perf)
168
+ if ( [ 'Element' , 'ReactElement' ] . every ( s => ! typeString . startsWith ( s ) ) ) return
169
+ const declFile = returnType . getSymbol ( ) ?. declarations ?. [ 0 ] ?. getSourceFile ( ) . fileName
170
+ if ( ! declFile ?. includes ( reactTypesPath ) ) return
171
+ return true
175
172
}
176
173
177
174
const getPossiblyJsxType = ( type : ts . Type ) => {
@@ -188,3 +185,37 @@ const getPossiblyJsxType = (type: ts.Type) => {
188
185
}
189
186
return type . flags & ts . TypeFlags . Object ? type : undefined
190
187
}
188
+
189
+ const getGlobalJsxElementType = ( program : ts . Program ) => {
190
+ const checker = getFullTypeChecker ( program . getTypeChecker ( ) )
191
+ const globalJsxNamespace = checker . resolveName ( 'JSX' , undefined , ts . SymbolFlags . Namespace , false )
192
+ if ( ! globalJsxNamespace ) return
193
+ const exportsSymbols = checker . getExportsOfModule ( globalJsxNamespace )
194
+ const symbolTable = tsFull . createSymbolTable ( exportsSymbols )
195
+ const elementSymbol = getSymbol ( checker , symbolTable , 'Element' , ts . SymbolFlags . Type )
196
+ if ( ! elementSymbol ) return
197
+ return checker . getDeclaredTypeOfSymbol ( elementSymbol )
198
+ }
199
+
200
+ function getSymbol (
201
+ checker : import ( 'typescript-full' ) . TypeChecker ,
202
+ symbols : import ( 'typescript-full' ) . SymbolTable ,
203
+ name : string ,
204
+ meaning : ts . SymbolFlags ,
205
+ ) : import ( 'typescript-full' ) . Symbol | undefined {
206
+ if ( meaning ) {
207
+ const symbol = checker . getMergedSymbol ( symbols . get ( name as ts . __String ) ! )
208
+ if ( symbol ) {
209
+ if ( symbol . flags & meaning ) {
210
+ return symbol
211
+ }
212
+ if ( symbol . flags & ts . SymbolFlags . Alias ) {
213
+ const target = checker . getAliasedSymbol ( symbol )
214
+ if ( checker . isUnknownSymbol ( target ) || target . flags & meaning ) {
215
+ return symbol
216
+ }
217
+ }
218
+ }
219
+ }
220
+ return undefined
221
+ }
0 commit comments