Skip to content

Commit 1fd263e

Browse files
committed
feat: enhance PhpDocTypeNodeToTypescriptTypeNodeTranspiler with importName and typeIdentifiers
- Added importName and typeIdentifiers to the nameNodePathResolver return type. - Updated logic to handle external types and generate import statements accordingly. - Improved type reference creation to support qualified names for multiple identifiers.
1 parent f0c5bef commit 1fd263e

2 files changed

Lines changed: 46 additions & 8 deletions

File tree

src/phpdoc-parser/transpiler/php-doc-to-typescript-type-transpiler.ts

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import {
22
factory,
3+
type Identifier,
34
type ImportDeclaration,
5+
type QualifiedName,
46
SyntaxKind,
57
type TypeNode,
68
} from 'typescript';
@@ -19,15 +21,19 @@ export type NameNodePathResolver<T> = (
1921
) => {
2022
path: string;
2123
name: string;
24+
importName: string;
2225
isTypeOnly: boolean;
26+
typeIdentifiers: string[];
2327
};
2428

2529
export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
2630
constructor(
2731
public nameNodePathResolver: (nodeParts: string[]) => {
2832
path: string;
2933
name: string;
34+
importName: string;
3035
isTypeOnly: boolean;
36+
typeIdentifiers: string[];
3137
},
3238
) {}
3339

@@ -87,6 +93,7 @@ export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
8793
'non-empty-array',
8894
'list',
8995
'non-empty-list',
96+
'\\Illuminate\\Support\\Collection',
9097
'\\Illuminate\\Database\\Eloquent\\Collection',
9198
].includes(sourceTypeNode.type.name)
9299
) {
@@ -167,7 +174,11 @@ export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
167174
return factory.createToken(SyntaxKind.VoidKeyword);
168175
}
169176

170-
if (sourceTypeNode.name === 'null') {
177+
if (
178+
['\\Illuminate\\Http\\Resources\\MissingValue', 'null'].includes(
179+
sourceTypeNode.name,
180+
)
181+
) {
171182
return factory.createLiteralTypeNode(factory.createNull());
172183
}
173184

@@ -179,10 +190,11 @@ export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
179190
if (/^[A-Z\\]/.test(sourceTypeNode.name)) {
180191
const nameNodeParts = sourceTypeNode.name.split('\\');
181192

182-
const { name, path, isTypeOnly } =
193+
const { path, isTypeOnly, importName, typeIdentifiers } =
183194
this.nameNodePathResolver(nameNodeParts);
184195

185-
if (name !== 'string' && path !== '') {
196+
// For external types, generate import statement
197+
if (importName !== 'string' && path !== '') {
186198
this.importDeclarations.push(
187199
factory.createImportDeclaration(
188200
undefined,
@@ -193,7 +205,7 @@ export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
193205
factory.createImportSpecifier(
194206
false,
195207
undefined,
196-
factory.createIdentifier(name),
208+
factory.createIdentifier(importName),
197209
),
198210
]),
199211
),
@@ -203,10 +215,30 @@ export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
203215
);
204216
}
205217

206-
return factory.createTypeReferenceNode(
207-
factory.createIdentifier(name),
208-
undefined,
218+
// Build qualified name recursively for multiple identifiers
219+
let typeNameNode: QualifiedName | Identifier = factory.createIdentifier(
220+
typeIdentifiers[0],
209221
);
222+
223+
// typeIdentifiers = ['RestaurantNamespace', 'IPizza']
224+
// factory.createQualifiedName(
225+
// factory.createIdentifier("RestaurantNamespace"),
226+
// factory.createIdentifier("IPizza")
227+
// )
228+
// ⬇️
229+
// export interface IMyOrder {
230+
// ...
231+
// pizza: RestaurantNamespace.IPizza;
232+
// ...
233+
// }
234+
for (let i = 1; i < typeIdentifiers.length; i += 1) {
235+
typeNameNode = factory.createQualifiedName(
236+
typeNameNode,
237+
factory.createIdentifier(typeIdentifiers[i]),
238+
);
239+
}
240+
241+
return factory.createTypeReferenceNode(typeNameNode, undefined);
210242
}
211243
}
212244

tests/transpiler/transpiler.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class ExtendedTranspiler extends PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
1919
resolver.call(this, nodeParts) as {
2020
path: string;
2121
name: string;
22+
importName: string;
23+
typeIdentifiers: string[];
2224
isTypeOnly: boolean;
2325
},
2426
);
@@ -49,10 +51,14 @@ const getPropertyTagValueNodesFromComment = (commentText: string) => {
4951
const nameNodePathResolver: NameNodePathResolver<ExtendedTranspiler> =
5052
// eslint-disable-next-line func-names
5153
function (this: ExtendedTranspiler, nodeParts: string[]) {
54+
const lastPart = nodeParts.at(-1);
55+
5256
return {
53-
name: nodeParts.at(-1),
57+
name: lastPart,
5458
path: '',
5559
isTypeOnly: false,
60+
importName: lastPart,
61+
typeIdentifiers: [lastPart],
5662
};
5763
};
5864

0 commit comments

Comments
 (0)