1
1
import {
2
2
factory ,
3
+ type Identifier ,
3
4
type ImportDeclaration ,
5
+ type QualifiedName ,
4
6
SyntaxKind ,
5
7
type TypeNode ,
6
8
} from 'typescript' ;
@@ -18,16 +20,18 @@ export type NameNodePathResolver<T> = (
18
20
nodeParts : string [ ] ,
19
21
) => {
20
22
path : string ;
21
- name : string ;
23
+ importName : string ;
22
24
isTypeOnly : boolean ;
25
+ typeIdentifiers : string [ ] ;
23
26
} ;
24
27
25
28
export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
26
29
constructor (
27
30
public nameNodePathResolver : ( nodeParts : string [ ] ) => {
28
31
path : string ;
29
- name : string ;
32
+ importName : string ;
30
33
isTypeOnly : boolean ;
34
+ typeIdentifiers : string [ ] ;
31
35
} ,
32
36
) { }
33
37
@@ -87,6 +91,7 @@ export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
87
91
'non-empty-array' ,
88
92
'list' ,
89
93
'non-empty-list' ,
94
+ '\\Illuminate\\Support\\Collection' ,
90
95
'\\Illuminate\\Database\\Eloquent\\Collection' ,
91
96
] . includes ( sourceTypeNode . type . name )
92
97
) {
@@ -167,7 +172,11 @@ export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
167
172
return factory . createToken ( SyntaxKind . VoidKeyword ) ;
168
173
}
169
174
170
- if ( sourceTypeNode . name === 'null' ) {
175
+ if (
176
+ [ '\\Illuminate\\Http\\Resources\\MissingValue' , 'null' ] . includes (
177
+ sourceTypeNode . name ,
178
+ )
179
+ ) {
171
180
return factory . createLiteralTypeNode ( factory . createNull ( ) ) ;
172
181
}
173
182
@@ -179,10 +188,11 @@ export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
179
188
if ( / ^ [ A - Z \\ ] / . test ( sourceTypeNode . name ) ) {
180
189
const nameNodeParts = sourceTypeNode . name . split ( '\\' ) ;
181
190
182
- const { name , path, isTypeOnly } =
191
+ const { path, isTypeOnly, importName , typeIdentifiers } =
183
192
this . nameNodePathResolver ( nameNodeParts ) ;
184
193
185
- if ( name !== 'string' && path !== '' ) {
194
+ // For external types, generate import statement
195
+ if ( importName !== 'string' && path !== '' ) {
186
196
this . importDeclarations . push (
187
197
factory . createImportDeclaration (
188
198
undefined ,
@@ -193,7 +203,7 @@ export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
193
203
factory . createImportSpecifier (
194
204
false ,
195
205
undefined ,
196
- factory . createIdentifier ( name ) ,
206
+ factory . createIdentifier ( importName ) ,
197
207
) ,
198
208
] ) ,
199
209
) ,
@@ -203,10 +213,30 @@ export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
203
213
) ;
204
214
}
205
215
206
- return factory . createTypeReferenceNode (
207
- factory . createIdentifier ( name ) ,
208
- undefined ,
216
+ // Build qualified name recursively for multiple identifiers
217
+ let typeNameNode : QualifiedName | Identifier = factory . createIdentifier (
218
+ typeIdentifiers [ 0 ] ,
209
219
) ;
220
+
221
+ // typeIdentifiers = ['RestaurantNamespace', 'IPizza']
222
+ // factory.createQualifiedName(
223
+ // factory.createIdentifier("RestaurantNamespace"),
224
+ // factory.createIdentifier("IPizza")
225
+ // )
226
+ // ⬇️
227
+ // export interface IMyOrder {
228
+ // ...
229
+ // pizza: RestaurantNamespace.IPizza;
230
+ // ...
231
+ // }
232
+ for ( let i = 1 ; i < typeIdentifiers . length ; i += 1 ) {
233
+ typeNameNode = factory . createQualifiedName (
234
+ typeNameNode ,
235
+ factory . createIdentifier ( typeIdentifiers [ i ] ) ,
236
+ ) ;
237
+ }
238
+
239
+ return factory . createTypeReferenceNode ( typeNameNode , undefined ) ;
210
240
}
211
241
}
212
242
0 commit comments