Skip to content

Commit 071e5ed

Browse files
authored
Merge pull request #331 from RightCapitalHQ/feature/php-doc-transpiler-improvements
feat(transpiler): enhance transpiler with importName and typeIdentifiers
2 parents f0c5bef + a94aa34 commit 071e5ed

File tree

4 files changed

+54
-12
lines changed

4 files changed

+54
-12
lines changed

_typos.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[default.extend-words]
22
Ue = "Ue"
33
ND = "ND"
4-
ba = "ba"
4+
ba = "ba"
5+
ede = "ede"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "minor",
3+
"comment": "feat: enhance PhpDocTypeNodeToTypescriptTypeNodeTranspiler with importName and typeIdentifiers",
4+
"packageName": "@rightcapital/phpdoc-parser",
5+
"email": "yilunsun11@yeah.net",
6+
"dependentChangeType": "patch"
7+
}

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

Lines changed: 39 additions & 9 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';
@@ -18,16 +20,18 @@ export type NameNodePathResolver<T> = (
1820
nodeParts: string[],
1921
) => {
2022
path: string;
21-
name: string;
23+
importName: string;
2224
isTypeOnly: boolean;
25+
typeIdentifiers: string[];
2326
};
2427

2528
export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
2629
constructor(
2730
public nameNodePathResolver: (nodeParts: string[]) => {
2831
path: string;
29-
name: string;
32+
importName: string;
3033
isTypeOnly: boolean;
34+
typeIdentifiers: string[];
3135
},
3236
) {}
3337

@@ -87,6 +91,7 @@ export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
8791
'non-empty-array',
8892
'list',
8993
'non-empty-list',
94+
'\\Illuminate\\Support\\Collection',
9095
'\\Illuminate\\Database\\Eloquent\\Collection',
9196
].includes(sourceTypeNode.type.name)
9297
) {
@@ -167,7 +172,11 @@ export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
167172
return factory.createToken(SyntaxKind.VoidKeyword);
168173
}
169174

170-
if (sourceTypeNode.name === 'null') {
175+
if (
176+
['\\Illuminate\\Http\\Resources\\MissingValue', 'null'].includes(
177+
sourceTypeNode.name,
178+
)
179+
) {
171180
return factory.createLiteralTypeNode(factory.createNull());
172181
}
173182

@@ -179,10 +188,11 @@ export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
179188
if (/^[A-Z\\]/.test(sourceTypeNode.name)) {
180189
const nameNodeParts = sourceTypeNode.name.split('\\');
181190

182-
const { name, path, isTypeOnly } =
191+
const { path, isTypeOnly, importName, typeIdentifiers } =
183192
this.nameNodePathResolver(nameNodeParts);
184193

185-
if (name !== 'string' && path !== '') {
194+
// For external types, generate import statement
195+
if (importName !== 'string' && path !== '') {
186196
this.importDeclarations.push(
187197
factory.createImportDeclaration(
188198
undefined,
@@ -193,7 +203,7 @@ export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
193203
factory.createImportSpecifier(
194204
false,
195205
undefined,
196-
factory.createIdentifier(name),
206+
factory.createIdentifier(importName),
197207
),
198208
]),
199209
),
@@ -203,10 +213,30 @@ export class PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
203213
);
204214
}
205215

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],
209219
);
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);
210240
}
211241
}
212242

tests/transpiler/transpiler.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ class ExtendedTranspiler extends PhpDocTypeNodeToTypescriptTypeNodeTranspiler {
1818
(nodeParts: string[]) =>
1919
resolver.call(this, nodeParts) as {
2020
path: string;
21-
name: string;
21+
importName: string;
22+
typeIdentifiers: string[];
2223
isTypeOnly: boolean;
2324
},
2425
);
@@ -49,10 +50,13 @@ const getPropertyTagValueNodesFromComment = (commentText: string) => {
4950
const nameNodePathResolver: NameNodePathResolver<ExtendedTranspiler> =
5051
// eslint-disable-next-line func-names
5152
function (this: ExtendedTranspiler, nodeParts: string[]) {
53+
const lastPart = nodeParts.at(-1);
54+
5255
return {
53-
name: nodeParts.at(-1),
5456
path: '',
5557
isTypeOnly: false,
58+
importName: lastPart,
59+
typeIdentifiers: [lastPart],
5660
};
5761
};
5862

0 commit comments

Comments
 (0)