11import { Response , Schema , Spec as Swagger } from 'swagger-schema-official' ;
2- import { Definition , MethodType , MustacheData , Parameter , Render , RenderFileName } from './types' ;
2+ import { Definition , Method , MethodType , MustacheData , Parameter , Property , Render , RenderFileName } from './types' ;
33import { camelCase , dereferenceType , determineDomain , fileName , prefixImportedModels , toTypescriptType , typeName } from './helper' ;
44
5+
56export function createMustacheViewModel ( swagger : Swagger ) : MustacheData {
6- const authorizedMethods = [ 'GET' , 'POST' , 'PUT' , 'DELETE' , 'PATCH' ] ;
77 return {
88 description : swagger . info . description || '' ,
99 isSecure : ! ! swagger . securityDefinitions ,
1010 swagger : swagger ,
1111 domain : determineDomain ( swagger ) ,
12- methods : [ ] . concat . apply ( [ ] , Object . entries ( swagger . paths )
13- . map (
14- ( [ path , api ] ) => Object . entries ( api )
15- . filter ( ( [ method , ] ) => authorizedMethods . indexOf ( method . toUpperCase ( ) ) !== - 1 ) // skip unsupported methods
16- . map (
17- ( [ method , op ] ) => ( {
18- path : path . replace ( / ( { .* ?} ) / g, '$$$1' ) ,
19- methodName : camelCase (
20- op . operationId
21- ? op . operationId
22- : console . error ( 'Method name could not be determined, operationID is undefined' )
23- ) ,
24- methodType : < MethodType > method . toUpperCase ( ) ,
25- summaryLines : op . description ? op . description . split ( '\n' ) : [ ] , // description summary is optional
26- isSecure : swagger . security !== undefined || op . security !== undefined ,
27- parameters : transformParameters ( op . parameters ) ,
28- hasJsonResponse : true ,
29- response : prefixImportedModels ( determineResponseType ( op . responses ) ) ,
30- } )
31- )
32- ) ) ,
12+ methods : parseMethods ( swagger ) ,
3313 definitions : parseDefinitions ( swagger . definitions )
3414 } ;
3515}
3616
17+ function parseMethods ( { paths, security} : Swagger ) : Method [ ] {
18+ const authorizedMethods = [ 'GET' , 'POST' , 'PUT' , 'DELETE' , 'PATCH' ] ;
19+
20+ return [ ] . concat . apply ( [ ] , Object . entries ( paths )
21+ . map ( ( [ pathName , apiPath ] ) => Object . entries ( apiPath )
22+ . filter ( ( [ methodType , ] ) => authorizedMethods . indexOf ( methodType . toUpperCase ( ) ) !== - 1 ) // skip unsupported methods
23+ . map ( ( [ methodType , operation ] ) => ( {
24+ path : pathName . replace ( / ( { .* ?} ) / g, '$$$1' ) ,
25+ methodName : camelCase (
26+ operation . operationId
27+ ? operation . operationId
28+ : console . error ( `Method name could not be determined, path will be used instead of operation id [ ${ pathName } ]` )
29+ ) ,
30+ methodType : methodType . toUpperCase ( ) as MethodType ,
31+ summaryLines : operation . description ? operation . description . split ( '\n' ) : [ ] , // description summary is optional
32+ isSecure : security !== undefined || operation . security !== undefined ,
33+ parameters : transformParameters ( operation . parameters ) ,
34+ hasJsonResponse : true ,
35+ response : prefixImportedModels ( determineResponseType ( operation . responses ) ) ,
36+ } )
37+ )
38+ ) ) ;
39+ }
40+
3741function parseDefinitions ( definitions : { [ definitionsName : string ] : Schema } = { } ) : Definition [ ] {
3842 return Object . entries ( definitions ) . map ( ( [ key , definition ] ) =>
3943 definition . enum && definition . enum . length !== 0
@@ -50,49 +54,51 @@ function defineEnum(enumSchema: (string | boolean | number | {})[], definitionKe
5054 } ) ) ,
5155 isEnum : true ,
5256 imports : [ ] ,
53- renderFileName : ( ) : RenderFileName => ( ( text : string , render : Render ) : string => fileName ( render ( text ) , 'enum' ) ) ,
57+ renderFileName : ( ) : RenderFileName => ( text : string , render : Render ) : string => fileName ( render ( text ) , 'enum' ) ,
5458 } ;
5559}
5660
57- function defineInterface ( schema : Schema , definitionKey : string ) : Definition {
58- const properties : Parameter [ ] = Object . entries < Schema > ( schema . properties || { } ) . map (
59- ( [ propVal , propIn ] : [ string , Schema ] ) => {
60- const property : Parameter = {
61- name : propVal ,
62- isRef : '$ref' in propIn || ( propIn . type === 'array' && propIn . items && '$ref' in propIn . items ) ,
63- isArray : propIn . type === 'array' ,
61+ function parseInterfaceProperties ( { properties } : Schema = { } ) : Property [ ] {
62+ return Object . entries < Schema > ( properties || { } ) . map (
63+ ( [ propName , propSchema ] : [ string , Schema ] ) => {
64+ const property : Property = {
65+ name : propName ,
66+ isRef : '$ref' in propSchema || ( propSchema . type === 'array' && propSchema . items && '$ref' in propSchema . items ) ,
67+ isArray : propSchema . type === 'array' ,
6468 } ;
6569
66- if ( Array . isArray ( propIn . items ) ) {
70+ if ( Array . isArray ( propSchema . items ) ) {
6771 console . warn ( 'Arrays with type diversity are currently not supported' ) ;
6872 property . type = 'any' ;
6973
7074 return property ;
7175 }
7276
7377 if ( property . isArray ) {
74- if ( propIn . items && propIn . items . $ref ) {
75- property . type = typeName ( dereferenceType ( propIn . items . $ref ) ) ;
76- } else if ( propIn . items && propIn . items . type ) {
77- property . type = typeName ( propIn . items . type ) ;
78+ if ( propSchema . items && propSchema . items . $ref ) {
79+ property . type = typeName ( dereferenceType ( propSchema . items . $ref ) ) ;
80+ } else if ( propSchema . items && propSchema . items . type ) {
81+ property . type = typeName ( propSchema . items . type ) ;
7882 } else {
79- property . type = propIn . type ;
83+ property . type = propSchema . type ;
8084 }
8185 } else {
8286 property . type = typeName (
83- propIn . $ref
84- ? dereferenceType ( propIn . $ref )
85- : propIn . type
87+ propSchema . $ref
88+ ? dereferenceType ( propSchema . $ref )
89+ : propSchema . type
8690 ) ;
8791 }
8892
89- property . typescriptType = toTypescriptType ( property ) ;
93+ property . typescriptType = toTypescriptType ( property . type , property . items ) ;
9094
9195 return property ;
9296 }
93- )
94- . sort ( ( a , b ) => a . name && b . name ? a . name . localeCompare ( b . name ) : - 1 ) ;
97+ ) . sort ( ( a , b ) => a . name && b . name ? a . name . localeCompare ( b . name ) : - 1 ) ;
98+ }
9599
100+ function defineInterface ( schema : Schema , definitionKey : string ) : Definition {
101+ const properties : Property [ ] = parseInterfaceProperties ( schema . properties ) ;
96102 const name = typeName ( definitionKey ) ;
97103
98104 return {
@@ -139,31 +145,28 @@ function transformParameters(parameters: Parameter[]): Parameter[] {
139145 return Array . isArray ( parameters )
140146 // todo: required params
141147 ? parameters . map ( ( param ) => {
142- const parameter = { ...param } ;
143-
144- if ( 'schema' in param && typeof param . schema . $ref === 'string' ) {
145- parameter . type = camelCase ( dereferenceType ( param . schema . $ref ) ) ;
146- }
148+ console . log ( '==>' , param ) ;
147149
148- parameter . camelCaseName = camelCase ( param . name ) ;
149- parameter . typescriptType = toTypescriptType ( parameter ) ;
150- parameter . importType = prefixImportedModels ( parameter . typescriptType ) ;
151-
152- if ( param . in === 'body' ) {
153- parameter . isBodyParameter = true ;
154- } else if ( param . in === 'path' ) {
155- // param is included in method path string interpolation
156- parameter . isPathParameter = true ;
157- } else if ( param . in === 'query' || param . in === 'modelbinding' ) {
158- parameter . isQueryParameter = true ;
159- } else if ( param . in === 'header' ) {
160- parameter . isHeaderParameter = true ;
161- } else if ( param . in === 'formData' ) {
162- parameter . isFormParameter = true ; // TODO: currently unsupported
163- console . warn ( `Form parameters are currently unsupported and will not be generated properly [ ${ param . name } ]` ) ;
164- }
165-
166- return parameter ;
150+ const typescriptType = toTypescriptType (
151+ dereferenceType ( param . $ref || ( 'schema' in param && param . schema . $ref ) ) || param . type ,
152+ param . items
153+ ) ;
154+ const camelCaseName = camelCase ( param . name ? param . name : typescriptType ) ; // if name is not defined, use type name
155+
156+ return {
157+ ...param ,
158+
159+ camelCaseName,
160+ importType : prefixImportedModels ( typescriptType ) ,
161+ isBodyParameter : param . in === 'body' ,
162+ isFormParameter : param . in === 'formData'
163+ ? console . warn ( `Form parameters are currently unsupported and will not be generated properly [ ${ param . name } ]` ) || true
164+ : false ,
165+ isHeaderParameter : param . in === 'header' ,
166+ isPathParameter : param . in === 'path' ,
167+ isQueryParameter : param . in === 'query' || param . in === 'modelbinding' ,
168+ typescriptType,
169+ } ;
167170 }
168171 )
169172 : [ ] ;
0 commit comments