@@ -161,9 +161,6 @@ type DeriveFunctionSchemaResult = {
161161}
162162
163163function deriveFunctionSchema ( functionDeclaration : ts . FunctionDeclaration , context : TypeDerivationContext ) : DeriveFunctionSchemaResult {
164- let functionIsBroken = false ;
165- const issues : string [ ] = [ ] ;
166-
167164 const functionIdentifier = functionDeclaration . name ?? throwError ( "Function didn't have an identifier" ) ;
168165 const functionName = functionIdentifier . text
169166 const functionSymbol = context . typeChecker . getSymbolAtLocation ( functionIdentifier ) ?? throwError ( `Function '${ functionName } ' didn't have a symbol` ) ;
@@ -173,52 +170,43 @@ function deriveFunctionSchema(functionDeclaration: ts.FunctionDeclaration, conte
173170 const markedPureInJsDoc = functionSymbol . getJsDocTags ( ) . find ( e => e . name === "pure" ) !== undefined ;
174171
175172 const functionCallSig = functionType . getCallSignatures ( ) [ 0 ] ?? throwError ( `Function '${ functionName } ' didn't have a call signature` )
176- const functionSchemaArguments : schema . ArgumentDefinition [ ] = functionCallSig . getParameters ( ) . flatMap ( paramSymbol => {
173+ const functionSchemaArguments : Result < schema . ArgumentDefinition [ ] , string [ ] > = Result . traverseAndCollectErrors ( functionCallSig . getParameters ( ) , paramSymbol => {
177174 const paramName = paramSymbol . getName ( ) ;
178175 const paramDesc = ts . displayPartsToString ( paramSymbol . getDocumentationComment ( context . typeChecker ) ) . trim ( ) ;
179176 const paramType = context . typeChecker . getTypeOfSymbolAtLocation ( paramSymbol , paramSymbol . valueDeclaration ?? throwError ( `Function '${ functionName } ' parameter '${ paramName } ' didn't have a value declaration` ) ) ;
180177 const paramTypePath : TypePathSegment [ ] = [ { segmentType : "FunctionParameter" , functionName, parameterName : paramName } ] ;
181178
182- const paramTypeResult = deriveSchemaTypeForTsType ( paramType , paramTypePath , context ) ;
183-
184- if ( paramTypeResult instanceof Err ) {
185- // Record the error, discard the parameter, but mark the function
186- // as broken so we discard the whole thing at the end
187- issues . push ( ...paramTypeResult . error )
188- functionIsBroken = true ;
189- return [ ] ;
190- } else {
191- issues . push ( ...paramTypeResult . data . warnings )
192- return [ {
179+ return deriveSchemaTypeForTsType ( paramType , paramTypePath , context )
180+ . map ( paramTypeResult => ( {
193181 argumentName : paramName ,
194182 description : paramDesc ? paramDesc : null ,
195- type : paramTypeResult . data . typeDefinition ,
196- } ]
197- }
183+ type : paramTypeResult ,
184+ } ) ) ;
198185 } ) ;
199186
200187 const returnType = functionCallSig . getReturnType ( ) ;
201188 const returnTypeResult = deriveSchemaTypeForTsType ( unwrapPromiseType ( returnType , context . typeChecker ) ?? returnType , [ { segmentType : "FunctionReturn" , functionName} ] , context ) ;
202- let functionDefinition : schema . FunctionDefinition | null = null ;
203- if ( returnTypeResult instanceof Err ) {
204- // Record the error, mark the function as broken so we discard the whole thing at the end
205- issues . push ( ...returnTypeResult . error )
206- functionIsBroken = true ;
207- functionDefinition = null ;
208- } else {
209- issues . push ( ...returnTypeResult . data . warnings )
210- functionDefinition = {
189+
190+ const functionDefinition = Result . collectErrors ( functionSchemaArguments , returnTypeResult )
191+ . map ( ( [ functionSchemaArgs , returnType ] ) => ( {
211192 description : functionDescription ? functionDescription : null ,
212193 ndcKind : markedPureInJsDoc ? schema . FunctionNdcKind . Function : schema . FunctionNdcKind . Procedure ,
213- arguments : functionSchemaArguments ,
214- resultType : returnTypeResult . data . typeDefinition
215- }
216- }
194+ arguments : functionSchemaArgs ,
195+ resultType : returnType
196+ } ) ) ;
217197
218- return {
219- name : functionName ,
220- definition : ! functionIsBroken ? functionDefinition : null ,
221- issues : issues
198+ if ( functionDefinition instanceof Err ) {
199+ return {
200+ name : functionName ,
201+ definition : null ,
202+ issues : functionDefinition . error
203+ }
204+ } else {
205+ return {
206+ name : functionName ,
207+ definition : functionDefinition . data ,
208+ issues : [ ]
209+ }
222210 }
223211}
224212
@@ -244,10 +232,7 @@ function typePathSegmentToString(segment: TypePathSegment): string {
244232 }
245233}
246234
247- type DerivedSchemaType =
248- { typeDefinition : schema . TypeDefinition , warnings : string [ ] }
249-
250- function deriveSchemaTypeForTsType ( tsType : ts . Type , typePath : TypePathSegment [ ] , context : TypeDerivationContext , recursionDepth : number = 0 ) : Result < DerivedSchemaType , string [ ] > {
235+ function deriveSchemaTypeForTsType ( tsType : ts . Type , typePath : TypePathSegment [ ] , context : TypeDerivationContext , recursionDepth : number = 0 ) : Result < schema . TypeDefinition , string [ ] > {
251236 const typeRenderedName = context . typeChecker . typeToString ( tsType ) ;
252237
253238 if ( recursionDepth > MAX_TYPE_DERIVATION_RECURSION )
@@ -310,68 +295,63 @@ function deriveSchemaTypeForTsType(tsType: ts.Type, typePath: TypePathSegment[],
310295 return new Err ( [ `Union types are not supported, but one was encountered in ${ typePathToString ( typePath ) } (type: ${ context . typeChecker . typeToString ( tsType ) } )` ] ) ;
311296 }
312297
313- // We don't know how to deal with this type, so just make it an opaque scalar
314- const typeName = generateTypeNameFromTypePath ( typePath ) ;
315- context . scalarTypeDefinitions [ typeName ] = { } ;
316- return new Ok ( {
317- warnings : [ `Unable to derive an NDC type for ${ typePathToString ( typePath ) } (type: ${ context . typeChecker . typeToString ( tsType ) } ). Assuming that it is a scalar type.` ] ,
318- typeDefinition : { type : "named" , kind : "scalar" , name : typeName }
319- } ) ;
298+ // We don't know how to deal with this type, so reject it with a generic error
299+ return new Err ( [ `Unable to derive an NDC type for ${ typePathToString ( typePath ) } (type: ${ context . typeChecker . typeToString ( tsType ) } ).` ] ) ;
320300}
321301
322- function deriveSchemaTypeIfTsArrayType ( tsType : ts . Type , typePath : TypePathSegment [ ] , context : TypeDerivationContext , recursionDepth : number ) : Result < DerivedSchemaType , string [ ] > | undefined {
302+ function deriveSchemaTypeIfTsArrayType ( tsType : ts . Type , typePath : TypePathSegment [ ] , context : TypeDerivationContext , recursionDepth : number ) : Result < schema . TypeDefinition , string [ ] > | undefined {
323303 if ( context . typeChecker . isArrayType ( tsType ) && tsutils . isTypeReference ( tsType ) ) {
324304 const typeArgs = context . typeChecker . getTypeArguments ( tsType )
325305 if ( typeArgs . length === 1 ) {
326306 const innerType = typeArgs [ 0 ] ! ;
327307 return deriveSchemaTypeForTsType ( innerType , [ ...typePath , { segmentType : "Array" } ] , context , recursionDepth + 1 )
328- . map ( innerTypeResult => ( { typeDefinition : { type : "array" , elementType : innerTypeResult . typeDefinition } , warnings : innerTypeResult . warnings } ) ) ;
308+ . map ( innerType => ( { type : "array" , elementType : innerType } ) ) ;
329309 }
330310 }
331311}
332312
333- function deriveSchemaTypeIfScalarType ( tsType : ts . Type , context : TypeDerivationContext ) : Result < DerivedSchemaType , string [ ] > | undefined {
313+ function deriveSchemaTypeIfScalarType ( tsType : ts . Type , context : TypeDerivationContext ) : Result < schema . TypeDefinition , string [ ] > | undefined {
334314 if ( tsutils . isIntrinsicBooleanType ( tsType ) ) {
335315 context . scalarTypeDefinitions [ schema . BuiltInScalarTypeName . Boolean ] = { } ;
336- return new Ok ( { typeDefinition : { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . Boolean } , warnings : [ ] } ) ;
316+ return new Ok ( { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . Boolean } ) ;
337317 }
338318 if ( tsutils . isBooleanLiteralType ( tsType ) ) {
339319 context . scalarTypeDefinitions [ schema . BuiltInScalarTypeName . Boolean ] = { } ;
340320 const literalValue = tsType . intrinsicName === "true" ? true : false ; // Unfortunately the types lie, tsType.value is undefined here :(
341- return new Ok ( { typeDefinition : { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . Boolean , literalValue : literalValue } , warnings : [ ] } ) ;
321+ return new Ok ( { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . Boolean , literalValue : literalValue } ) ;
342322 }
343323 if ( tsutils . isIntrinsicStringType ( tsType ) ) {
344324 context . scalarTypeDefinitions [ schema . BuiltInScalarTypeName . String ] = { } ;
345- return new Ok ( { typeDefinition : { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . String } , warnings : [ ] } ) ;
325+ return new Ok ( { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . String } ) ;
346326 }
347327 if ( tsutils . isStringLiteralType ( tsType ) ) {
348328 context . scalarTypeDefinitions [ schema . BuiltInScalarTypeName . String ] = { } ;
349- return new Ok ( { typeDefinition : { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . String , literalValue : tsType . value } , warnings : [ ] } ) ;
329+ return new Ok ( { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . String , literalValue : tsType . value } ) ;
350330 }
351331 if ( tsutils . isIntrinsicNumberType ( tsType ) ) {
352332 context . scalarTypeDefinitions [ schema . BuiltInScalarTypeName . Float ] = { } ;
353- return new Ok ( { typeDefinition : { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . Float } , warnings : [ ] } ) ;
333+ return new Ok ( { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . Float } ) ;
354334 }
355335 if ( tsutils . isNumberLiteralType ( tsType ) ) {
356336 context . scalarTypeDefinitions [ schema . BuiltInScalarTypeName . Float ] = { } ;
357- return new Ok ( { typeDefinition : { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . Float , literalValue : tsType . value } , warnings : [ ] } ) ;
337+ return new Ok ( { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . Float , literalValue : tsType . value } ) ;
358338 }
359339 if ( tsutils . isIntrinsicBigIntType ( tsType ) ) {
360340 context . scalarTypeDefinitions [ schema . BuiltInScalarTypeName . BigInt ] = { } ;
361- return new Ok ( { typeDefinition : { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . BigInt } , warnings : [ ] } ) ;
341+ return new Ok ( { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . BigInt } ) ;
362342 }
363343 if ( tsutils . isBigIntLiteralType ( tsType ) ) {
364344 context . scalarTypeDefinitions [ schema . BuiltInScalarTypeName . BigInt ] = { } ;
365345 const literalValue = BigInt ( `${ tsType . value . negative ? "-" : "" } ${ tsType . value . base10Value } ` ) ;
366- return new Ok ( { typeDefinition : { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . BigInt , literalValue : literalValue } , warnings : [ ] } ) ;
346+ return new Ok ( { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . BigInt , literalValue : literalValue } ) ;
367347 }
368348 if ( isDateType ( tsType ) ) {
369349 context . scalarTypeDefinitions [ schema . BuiltInScalarTypeName . DateTime ] = { } ;
370- return new Ok ( { typeDefinition : { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . DateTime } , warnings : [ ] } ) ;
350+ return new Ok ( { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . DateTime } ) ;
371351 }
372352 if ( isJSONValueType ( tsType , context . ndcLambdaSdkModule ) ) {
373353 context . scalarTypeDefinitions [ schema . BuiltInScalarTypeName . JSON ] = { } ;
374- return new Ok ( { typeDefinition : { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . JSON } , warnings : [ ] } ) ;
354+ return new Ok ( { type : "named" , kind : "scalar" , name : schema . BuiltInScalarTypeName . JSON } ) ;
375355 }
376356}
377357
@@ -401,37 +381,33 @@ function isJSONValueType(tsType: ts.Type, ndcLambdaSdkModule: ts.ResolvedModuleF
401381 return sourceFile . fileName . startsWith ( sdkDirectory ) ;
402382}
403383
404- function deriveSchemaTypeIfNullableType ( tsType : ts . Type , typePath : TypePathSegment [ ] , context : TypeDerivationContext , recursionDepth : number ) : Result < DerivedSchemaType , string [ ] > | undefined {
384+ function deriveSchemaTypeIfNullableType ( tsType : ts . Type , typePath : TypePathSegment [ ] , context : TypeDerivationContext , recursionDepth : number ) : Result < schema . TypeDefinition , string [ ] > | undefined {
405385 const notNullableResult = unwrapNullableType ( tsType ) ;
406386 if ( notNullableResult !== null ) {
407387 const [ notNullableType , nullOrUndefinability ] = notNullableResult ;
408388 return deriveSchemaTypeForTsType ( notNullableType , typePath , context , recursionDepth + 1 )
409- . map ( notNullableTypeResult => ( { typeDefinition : { type : "nullable" , underlyingType : notNullableTypeResult . typeDefinition , nullOrUndefinability } , warnings : notNullableTypeResult . warnings } ) )
389+ . map ( notNullableType => ( { type : "nullable" , underlyingType : notNullableType , nullOrUndefinability } ) )
410390 }
411391}
412392
413- function deriveSchemaTypeIfObjectType ( tsType : ts . Type , typePath : TypePathSegment [ ] , context : TypeDerivationContext , recursionDepth : number ) : Result < DerivedSchemaType , string [ ] > | undefined {
393+ function deriveSchemaTypeIfObjectType ( tsType : ts . Type , typePath : TypePathSegment [ ] , context : TypeDerivationContext , recursionDepth : number ) : Result < schema . TypeDefinition , string [ ] > | undefined {
414394 const info = getObjectTypeInfo ( tsType , typePath , context . typeChecker , context . functionsFilePath ) ;
415395 if ( info ) {
416396 // Short-circuit recursion if the type has already been named
417397 if ( context . objectTypeDefinitions [ info . generatedTypeName ] ) {
418- return new Ok ( { typeDefinition : { type : 'named' , name : info . generatedTypeName , kind : "object" } , warnings : [ ] } ) ;
398+ return new Ok ( { type : 'named' , name : info . generatedTypeName , kind : "object" } ) ;
419399 }
420400
421401 context . objectTypeDefinitions [ info . generatedTypeName ] = { properties : [ ] } ; // Break infinite recursion
422402
423- const warnings : string [ ] = [ ] ;
424403 const propertyResults = Result . traverseAndCollectErrors ( Array . from ( info . members ) , ( [ propertyName , propertyType ] ) => {
425404 return deriveSchemaTypeForTsType ( propertyType , [ ...typePath , { segmentType : "ObjectProperty" , typeName : info . generatedTypeName , propertyName } ] , context , recursionDepth + 1 )
426- . map ( propertyTypeResult => {
427- warnings . push ( ...propertyTypeResult . warnings )
428- return { propertyName : propertyName , type : propertyTypeResult . typeDefinition }
429- } ) ;
405+ . map ( propertyType => ( { propertyName : propertyName , type : propertyType } ) ) ;
430406 } ) ;
431407
432408 if ( propertyResults instanceof Ok ) {
433409 context . objectTypeDefinitions [ info . generatedTypeName ] = { properties : propertyResults . data }
434- return new Ok ( { typeDefinition : { type : 'named' , name : info . generatedTypeName , kind : "object" } , warnings } )
410+ return new Ok ( { type : 'named' , name : info . generatedTypeName , kind : "object" } )
435411 } else {
436412 // Remove the recursion short-circuit to ensure errors are raised if this type is encountered again
437413 delete context . objectTypeDefinitions [ info . generatedTypeName ] ;
0 commit comments