Skip to content

Commit 85c49d8

Browse files
committed
feat: improve sample generation in getValueFromType to prevent infinite recursion and enhance object handling
1 parent 24c1428 commit 85c49d8

2 files changed

Lines changed: 23 additions & 12 deletions

File tree

src/extraction/getValueFromType.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ export const getValueFromType = (
3636
* Recursively generates a sample JavaScript value for a given TypeScript Type.
3737
*/
3838
const generateSample = (t: ts.Type, node: ts.Node, visited = new Set<ts.Type>()): any => {
39-
if (visited.has(t)) return null;
40-
visited.add(t);
39+
// Create a NEW visited set for each object/array to avoid blocking reuse of primitive types
40+
// We only want to prevent infinite recursion on the SAME OBJECT, not on primitive types
41+
const localVisited = new Set(visited);
42+
43+
if (localVisited.has(t)) return null;
4144

4245
const flags = t.getFlags();
4346

@@ -49,15 +52,15 @@ export const getValueFromType = (
4952
if (ts.isTypeAliasDeclaration(node) && node.type && ts.isUnionTypeNode(node.type)) {
5053
// Try to follow the order in the source code if we are at the top level
5154
const firstType = checker.getTypeFromTypeNode(node.type.types[0]);
52-
return generateSample(firstType, node, visited);
55+
return generateSample(firstType, node, localVisited);
5356
}
5457

5558
const filteredTypes = t.types.filter(subType => {
5659
const f = subType.getFlags();
5760
return !(f & ts.TypeFlags.Undefined) && !(f & ts.TypeFlags.Null);
5861
});
5962
const typeToUse = filteredTypes.length > 0 ? filteredTypes[0] : t.types[0];
60-
return generateSample(typeToUse, node, visited);
63+
return generateSample(typeToUse, node, localVisited);
6164
}
6265

6366
// 2. Handle Primitives and Literals
@@ -72,21 +75,24 @@ export const getValueFromType = (
7275

7376
// 3. Handle Arrays
7477
if (checker.isArrayType(t)) {
78+
localVisited.add(t);
7579
const typeRef = t as ts.TypeReference;
7680
const elementType = typeRef.typeArguments?.[0] || checker.getAnyType();
77-
const sample = generateSample(elementType, node, visited);
81+
const sample = generateSample(elementType, node, localVisited);
7882
return sample !== null ? [sample] : [];
7983
}
8084

8185
// 4. Handle Objects / Interfaces
8286
if (t.isClassOrInterface() || (flags & ts.TypeFlags.Object) || t.getProperties().length > 0) {
87+
localVisited.add(t);
8388
const obj: any = {};
8489
const props = t.getProperties();
8590

8691
props.forEach(prop => {
8792
const propType = checker.getTypeOfSymbolAtLocation(prop, node);
93+
const propDeclaration = prop.valueDeclaration;
8894
if (propType) {
89-
obj[prop.getName()] = generateSample(propType, node, visited);
95+
obj[prop.getName()] = generateSample(propType, propDeclaration || node, localVisited);
9096
}
9197
});
9298
return obj;

test/valueFromType.test.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,20 @@ describe('getValueFromType', () => {
7575
});
7676

7777
it('sollte Objekte innerhalb von Listen füllen', () => {
78-
const type = 'LIST<{ uid: TEXT, tags: LIST<NUMBER> }>';
78+
const type = `{ body: { userNames: LIST<TEXT> }, headers: { Authorization: TEXT } }
79+
`;
7980
const result = getValueFromType(type, DATA_TYPES);
8081

81-
expect(result.value).toEqual([
82-
{
83-
uid: '',
84-
tags: [0]
82+
console.log(result)
83+
84+
expect(result.value).toEqual({
85+
body: {
86+
userNames: ['']
87+
},
88+
headers: {
89+
Authorization: ''
8590
}
86-
]);
91+
});
8792
});
8893
});
8994

0 commit comments

Comments
 (0)