1+ import ts from "typescript" ;
2+ import { LiteralValue } from "@code0-tech/sagittarius-graphql-types" ;
3+ import { createCompilerHost , DEFAULT_COMPILER_OPTIONS , ExtendedDataType , getSharedTypeDeclarations } from "../utils" ;
4+
5+ /**
6+ * Generates a sample LiteralValue from a TypeScript type string.
7+ */
8+ export const getValueFromType = (
9+ type : string ,
10+ dataTypes : ExtendedDataType [ ]
11+ ) : LiteralValue => {
12+ // 1. Prepare declarations.
13+ const sourceCode = `
14+ ${ getSharedTypeDeclarations ( dataTypes ) }
15+ type Target = ${ type } ;
16+ ` ;
17+
18+ const fileName = "temp_type_to_value.ts" ;
19+ const sourceFile = ts . createSourceFile ( fileName , sourceCode , ts . ScriptTarget . Latest , true ) ;
20+
21+ // 2. Setup the compiler context.
22+ const host = createCompilerHost ( fileName , sourceCode , sourceFile ) ;
23+
24+ const program = ts . createProgram ( [ fileName ] , DEFAULT_COMPILER_OPTIONS , host ) ;
25+
26+ const checker = program . getTypeChecker ( ) ;
27+
28+ // 3. Find the Target type alias.
29+ const targetNode = sourceFile . statements . find (
30+ ( s ) : s is ts . TypeAliasDeclaration => ts . isTypeAliasDeclaration ( s ) && s . name . text === "Target"
31+ ) ;
32+
33+ if ( ! targetNode ) {
34+ return { __typename : 'LiteralValue' , value : null } ;
35+ }
36+
37+ const typeFound = checker . getTypeAtLocation ( targetNode . type ) ;
38+
39+ /**
40+ * Recursively generates a sample JavaScript value for a given TypeScript Type.
41+ */
42+ const generateSample = ( t : ts . Type , node : ts . Node , visited = new Set < ts . Type > ( ) ) : any => {
43+ if ( visited . has ( t ) ) return null ;
44+ visited . add ( t ) ;
45+
46+ const flags = t . getFlags ( ) ;
47+
48+ // 1. Handle Union Types (e.g., "A" | "B" or string | number)
49+ if ( t . isUnion ( ) ) {
50+ // Pick types based on precedence to ensure deterministic results.
51+ // If the user provided multiple types in the union, pick the first non-null/undefined one.
52+ const typeNode = ( node as any ) . type ;
53+ if ( ts . isTypeAliasDeclaration ( node ) && node . type && ts . isUnionTypeNode ( node . type ) ) {
54+ // Try to follow the order in the source code if we are at the top level
55+ const firstType = checker . getTypeFromTypeNode ( node . type . types [ 0 ] ) ;
56+ return generateSample ( firstType , node , visited ) ;
57+ }
58+
59+ const filteredTypes = t . types . filter ( subType => {
60+ const f = subType . getFlags ( ) ;
61+ return ! ( f & ts . TypeFlags . Undefined ) && ! ( f & ts . TypeFlags . Null ) ;
62+ } ) ;
63+ const typeToUse = filteredTypes . length > 0 ? filteredTypes [ 0 ] : t . types [ 0 ] ;
64+ return generateSample ( typeToUse , node , visited ) ;
65+ }
66+
67+ // 2. Handle Primitives and Literals
68+ if ( flags & ts . TypeFlags . StringLiteral ) return ( t as ts . StringLiteralType ) . value ;
69+ if ( flags & ts . TypeFlags . String ) return "sample" ;
70+
71+ if ( flags & ts . TypeFlags . NumberLiteral ) return ( t as ts . NumberLiteralType ) . value ;
72+ if ( flags & ts . TypeFlags . Number ) return 1 ;
73+
74+ if ( flags & ts . TypeFlags . BooleanLiteral ) return ( t as any ) . intrinsicName === "true" ;
75+ if ( flags & ts . TypeFlags . Boolean ) return false ;
76+
77+ // 3. Handle Arrays
78+ if ( checker . isArrayType ( t ) ) {
79+ const typeRef = t as ts . TypeReference ;
80+ const elementType = typeRef . typeArguments ?. [ 0 ] || checker . getAnyType ( ) ;
81+ return [ generateSample ( elementType , node , visited ) ] ;
82+ }
83+
84+ // 4. Handle Objects / Interfaces
85+ if ( t . isClassOrInterface ( ) || ( flags & ts . TypeFlags . Object ) || t . getProperties ( ) . length > 0 ) {
86+ const obj : any = { } ;
87+ const props = t . getProperties ( ) ;
88+
89+ props . forEach ( prop => {
90+ const propType = checker . getTypeOfSymbolAtLocation ( prop , node ) ;
91+ if ( propType ) {
92+ obj [ prop . getName ( ) ] = generateSample ( propType , node , visited ) ;
93+ }
94+ } ) ;
95+ return obj ;
96+ }
97+
98+ return null ;
99+ } ;
100+
101+ const sample = generateSample ( typeFound , targetNode ) ;
102+
103+ // Test Expectation: result.value should be null for unknown types.
104+ // However, if we return null from the function, result.value access fails.
105+ // So we return an object { value: null } if sample is null.
106+ return {
107+ value : sample
108+ } ;
109+ } ;
0 commit comments