import { TypeAssertion , PrimitiveTypeAssertion , PrimitiveValueTypeAssertion , RepeatedAssertion , SpreadAssertion , SequenceAssertion , OneOfAssertion , EnumAssertion , ObjectAssertion , TypeAssertionMap , CodegenContext } from '../../types' ; function formatTypeName ( ty , ctx , typeName ) { if ( typeName . includes ( '.' ) ) { return generateGraphQlCodeInner ( ty , false , ctx , false ) ; } return typeName ; } function formatGraphQlCodeDocComment ( ty , nestLevel ) { let code = '' ; const indent = '    ' . repeat ( nestLevel ) ; const docComment = typeof ty === 'string' ? ty : ty . docComment ; if ( docComment ) { if ( 0 <= docComment . indexOf ( '\n' ) ) { code += `${ indent }/**\n${ indent }  ${ docComment . split ( '\n' ) . map ( x => x . trimLeft ( ) ) . join ( `\n${ indent } ` ) }\n${ indent } */\n` ; } else { code += `${ indent }/** ${ docComment } */\n` ; } } return code ; } function isNullableOneOf ( ty , ctx ) { const filtered = ty . oneOf . filter ( x => ! ( x . kind === 'primitive' && ( x . primitiveName === 'null' || x . primitiveName === 'undefined' ) || x . kind === 'primitive-value' && ( x . value === null || x . value === void 0 ) ) ) ; return ( filtered . length === 1 && ty . oneOf . length !== 1 ? filtered [ 0 ] : null ) ; } function generateGraphQlCodePrimitive ( ty , ctx ) { switch ( ty . primitiveName ) { case 'number' : return 'Float' ; case 'integer' : return 'Int' ; case 'bigint' : return 'BigInt' ; case 'string' : return 'String' ; case 'boolean' : return 'Boolean' ; case 'undefined' : case 'null' : default : return 'Any' ; } } function generateGraphQlCodePrimitiveValue ( ty , ctx ) { if ( ty . value === null ) { return 'Any' ; } if ( ty . value === void 0 ) { return 'Any' ; } switch ( typeof ty . value ) { case 'number' : return 'Float' ; case 'bigint' : return 'BigInt' ; case 'string' : return 'String' ; case 'boolean' : return 'Boolean' ; default : return 'Any' ; } } function generateGraphQlCodeRepeated ( ty , ctx ) { return ( `[${ ty . repeated . typeName ? formatTypeName ( ty . repeated , ctx , ty . repeated . typeName ) : generateGraphQlCodeInner ( ty . repeated , false , ctx , false ) }${ ( ty . repeated . kind === 'optional' || ty . repeated . kind === 'one-of' && isNullableOneOf ( ty . repeated , ctx ) ) ? '' : '!' }]` ) ; } function generateGraphQlCodeSpread ( ty , ctx ) { return '' ; } function generateGraphQlCodeSequence ( ty , ctx ) { return '[Any]' ; } function generateGraphQlCodeOneOf ( ty , ctx , isUnion ) { const z = isNullableOneOf ( ty , ctx ) ; if ( z ) { return z . typeName ? z . typeName : generateGraphQlCodeInner ( z , false , ctx , false ) ; } else { if ( isUnion ) { return `${ ty . oneOf . map ( x => x . typeName ? x . typeName : generateGraphQlCodeInner ( x , false , ctx , false ) ) . join ( ' | ' ) }` ; } else { return 'Any' ; } } } function generateGraphQlCodeEnum ( ty , ctx ) { return ( ty . typeName ? formatTypeName ( ty , ctx , ty . typeName ) : 'Any' ) ; } function generateGraphQlCodeObject ( ty , isInterface , ctx ) { if ( ty . members . length === 0 ) { return '{}' ; } const sep = '\n' ; const memberLines = ty . members . map ( x => `${ formatGraphQlCodeDocComment ( x [ 3 ] || '' , ctx . nestLevel + 1 ) }${ '    ' . repeat ( ctx . nestLevel + 1 ) }${ x [ 0 ] }: ${ x [ 1 ] . typeName ? formatTypeName ( x [ 1 ] , { ... ctx , nestLevel : ctx . nestLevel + 1 } , x [ 1 ] . typeName ) : generateGraphQlCodeInner ( x [ 1 ] , false , { ... ctx , nestLevel : ctx . nestLevel + 1 } , false ) }${ ( x [ 1 ] . kind === 'optional' || x [ 1 ] . kind === 'one-of' && isNullableOneOf ( x [ 1 ] , ctx ) ) ? '' : '!' }` ) ; return ( `{\n${ memberLines . join ( sep ) }${ sep }${ '    ' . repeat ( ctx . nestLevel ) }}` ) ; } function generateGraphQlCodeInner ( ty , isInterface , ctx , isUnion ) { let ret = '' ; switch ( ty . kind ) { case 'optional' : return generateGraphQlCodeInner ( ty . optional , isInterface , ctx , false ) ; case 'one-of' : return generateGraphQlCodeOneOf ( ty , ctx , isUnion ) ; case 'spread' : return generateGraphQlCodeSpread ( ty , ctx ) ; case 'sequence' : return generateGraphQlCodeSequence ( ty , ctx ) ; case 'never' : ret = 'Any' ; break ; case 'any' : ret = 'Any' ; break ; case 'unknown' : ret = 'Any' ; break ; case 'primitive' : ret = generateGraphQlCodePrimitive ( ty , ctx ) ; break ; case 'primitive-value' : ret = generateGraphQlCodePrimitiveValue ( ty , ctx ) ; break ; case 'repeated' : ret = generateGraphQlCodeRepeated ( ty , ctx ) ; break ; case 'enum' : ret = generateGraphQlCodeEnum ( ty , ctx ) ; break ; case 'object' : ret = generateGraphQlCodeObject ( ty , isInterface , ctx ) ; break ; case 'symlink' : ret = ty . symlinkTargetName ; break ; case 'operator' : throw new Error ( `Unexpected type assertion: ${ ( ty as any ) . kind }` ) ; default : throw new Error ( `Unknown type assertion: ${ ( ty as any ) . kind }` ) ; } return ret + '' ; } export function generateGraphQlCode ( types ) { let code = `\nscalar Any\nunion BigInt = String | Int\n\n` ; const ctx = { nestLevel : 0 } ; for ( const ty of types . entries ( ) ) { if ( ty [ 1 ] . ty . noOutput ) { code += `scalar ${ ty [ 0 ] }\n\n` ; continue ; } code += formatGraphQlCodeDocComment ( ty [ 1 ] . ty , ctx . nestLevel ) ; if ( ty [ 1 ] . ty . kind === 'object' ) { code += `type ${ ty [ 0 ] } ${ generateGraphQlCodeInner ( ty [ 1 ] . ty , true , ctx , false ) }\n\n` ; } else if ( ty [ 1 ] . ty . kind === 'enum' ) { const indent0 = '    ' . repeat ( ctx . nestLevel ) ; const indent1 = '    ' . repeat ( ctx . nestLevel + 1 ) ; code += `enum ${ ty [ 0 ] } {\n${ ty [ 1 ] . ty . values . map ( x => `${ formatGraphQlCodeDocComment ( x [ 2 ] || '' , ctx . nestLevel + 1 ) }${ indent1 }${ x [ 0 ] }\n` ) . join ( '' ) }${ indent0 }}\n\n` ; } else if ( ty [ 1 ] . ty . kind === 'never' && ty [ 1 ] . ty . passThruCodeBlock ) { } else { code += `union ${ ty [ 0 ] } = ${ generateGraphQlCodeInner ( ty [ 1 ] . ty , false , ctx , true ) }\n\n` ; } } return code ; }