1
1
import {
2
+ TAllOfSchemaObject ,
2
3
TBodyParameterObject ,
3
4
TDefinitionsObject ,
4
5
TNonArrayItemsObject ,
8
9
TPathParameterObject ,
9
10
TPathsObject ,
10
11
TQueryParameterObject ,
12
+ TReferenceSchemaObject ,
11
13
TResponseObject ,
12
14
TResponsesObject ,
13
15
TSchemaObject ,
@@ -32,7 +34,7 @@ import { intercalate } from 'fp-ts/lib/Foldable2v';
32
34
import { collect , lookup } from 'fp-ts/lib/Record' ;
33
35
import { identity } from 'fp-ts/lib/function' ;
34
36
35
- const EMPTY_DEPENDENCIES : TDepdendency [ ] = [ ] ;
37
+ const EMPTY_DEPENDENCIES : TDependency [ ] = [ ] ;
36
38
const EMPTY_REFS : string [ ] = [ ] ;
37
39
const SUCCESSFUL_CODES = [ '200' , 'default' ] ;
38
40
@@ -41,17 +43,17 @@ const concatIf = <A>(condition: boolean, as: A[], a: A[]): A[] => concatIfL(cond
41
43
const unless = ( condition : boolean , a : string ) : string => ( condition ? '' : a ) ;
42
44
const when = ( condition : boolean , a : string ) : string => ( condition ? a : '' ) ;
43
45
44
- type TDepdendency = {
46
+ type TDependency = {
45
47
name : string ;
46
48
path : string ;
47
49
} ;
48
50
type TSerializedType = {
49
51
type : string ;
50
52
io : string ;
51
- dependencies : TDepdendency [ ] ;
53
+ dependencies : TDependency [ ] ;
52
54
refs : string [ ] ;
53
55
} ;
54
- const serializedType = ( type : string , io : string , dependencies : TDepdendency [ ] , refs : string [ ] ) : TSerializedType => ( {
56
+ const serializedType = ( type : string , io : string , dependencies : TDependency [ ] , refs : string [ ] ) : TSerializedType => ( {
55
57
type,
56
58
io,
57
59
dependencies,
@@ -65,7 +67,7 @@ const serializedParameter = (
65
67
type : string ,
66
68
io : string ,
67
69
isRequired : boolean ,
68
- dependencies : TDepdendency [ ] ,
70
+ dependencies : TDependency [ ] ,
69
71
refs : string [ ] ,
70
72
) : TSerializedParameter => ( {
71
73
type,
@@ -82,7 +84,7 @@ const serializedPathParameter = (
82
84
type : string ,
83
85
io : string ,
84
86
isRequired : boolean ,
85
- dependencies : TDepdendency [ ] ,
87
+ dependencies : TDependency [ ] ,
86
88
refs : string [ ] ,
87
89
) : TSerializedPathParameter => ( {
88
90
name,
@@ -92,15 +94,15 @@ const serializedPathParameter = (
92
94
dependencies,
93
95
refs,
94
96
} ) ;
95
- const dependency = ( name : string , path : string ) : TDepdendency => ( {
97
+ const dependency = ( name : string , path : string ) : TDependency => ( {
96
98
name,
97
99
path,
98
100
} ) ;
99
101
const dependencyOption = dependency ( 'Option' , 'fp-ts/lib/Option' ) ;
100
102
const dependencyCreateOptionFromNullable = dependency ( 'createOptionFromNullable' , 'io-ts-types' ) ;
101
- const OPTION_DEPENDENCIES : TDepdendency [ ] = [ dependencyOption , dependencyCreateOptionFromNullable ] ;
103
+ const OPTION_DEPENDENCIES : TDependency [ ] = [ dependencyOption , dependencyCreateOptionFromNullable ] ;
102
104
103
- const monoidDependencies = getArrayMonoid < TDepdendency > ( ) ;
105
+ const monoidDependencies = getArrayMonoid < TDependency > ( ) ;
104
106
const monoidRefs = getArrayMonoid < string > ( ) ;
105
107
const monoidSerializedType = getRecordMonoid < TSerializedType > ( {
106
108
type : monoidString ,
@@ -210,47 +212,65 @@ const serializePath = (url: string, item: TPathItemObject, rootName: string, cwd
210
212
const get = item . get . map ( operation => serializeOperationObject ( url , 'GET' , operation , rootName , cwd ) ) ;
211
213
const put = item . put . map ( operation => serializeOperationObject ( url , 'PUT' , operation , rootName , cwd ) ) ;
212
214
const post = item . post . map ( operation => serializeOperationObject ( url , 'POST' , operation , rootName , cwd ) ) ;
213
- const remove = item [ ' delete' ] . map ( operation => serializeOperationObject ( url , 'DELETE' , operation , rootName , cwd ) ) ;
215
+ const remove = item . delete . map ( operation => serializeOperationObject ( url , 'DELETE' , operation , rootName , cwd ) ) ;
214
216
const options = item . options . map ( operation => serializeOperationObject ( url , 'OPTIONS' , operation , rootName , cwd ) ) ;
215
217
const head = item . head . map ( operation => serializeOperationObject ( url , 'HEAD' , operation , rootName , cwd ) ) ;
216
218
const patch = item . patch . map ( operation => serializeOperationObject ( url , 'PATCH' , operation , rootName , cwd ) ) ;
217
219
const operations = catOptions ( [ get , put , post , remove , options , head , patch ] ) ;
218
220
return foldSerialized ( operations ) ;
219
221
} ;
220
222
223
+ const is$ref = ( a : TReferenceSchemaObject | TAllOfSchemaObject ) : a is TReferenceSchemaObject =>
224
+ Object . prototype . hasOwnProperty . bind ( a ) ( '$ref' ) ;
225
+
221
226
const serializeSchemaObject = ( schema : TSchemaObject , rootName : string , cwd : string ) : TSerializedType => {
222
227
switch ( schema . type ) {
223
228
case undefined : {
224
- const $ref = schema . $ref ;
225
- const defBlock = fromNullable ( $ref . match ( / # \/ [ ^ \/ ] + \/ / ) )
226
- . chain ( head )
227
- . map ( def => def . replace ( / [ # , \/ ] / g, '' ) ) ;
228
- const refFileName = fromNullable ( $ref . match ( / ^ \. \/ [ ^ \/ ] + \. [ ^ \/ ] + # / ) )
229
- . chain ( head )
230
- . map ( ref => ref . replace ( / ( \. \/ | \. [ ^ / ] + # ) / g, '' ) ) ;
231
- const safeType = fromNullable ( $ref . match ( / \/ [ ^ \/ ] + $ / ) )
232
- . chain ( head )
233
- . map ( type => type . replace ( / ^ \/ / , '' ) ) ;
234
-
235
- if ( safeType . isNone ( ) || defBlock . isNone ( ) ) {
236
- throw new Error ( `Invalid $ref: ${ $ref } ` ) ;
229
+ if ( is$ref ( schema ) ) {
230
+ const $ref = schema . $ref ;
231
+ const defBlock = fromNullable ( $ref . match ( / # \/ [ ^ \/ ] + \/ / ) )
232
+ . chain ( head )
233
+ . map ( def => def . replace ( / [ # , \/ ] / g, '' ) ) ;
234
+ const refFileName = fromNullable ( $ref . match ( / ^ \. \/ [ ^ \/ ] + \. [ ^ \/ ] + # / ) )
235
+ . chain ( head )
236
+ . map ( ref => ref . replace ( / ( \. \/ | \. [ ^ / ] + # ) / g, '' ) ) ;
237
+ const safeType = fromNullable ( $ref . match ( / \/ [ ^ \/ ] + $ / ) )
238
+ . chain ( head )
239
+ . map ( type => type . replace ( / ^ \/ / , '' ) ) ;
240
+
241
+ if ( safeType . isNone ( ) || defBlock . isNone ( ) ) {
242
+ throw new Error ( `Invalid $ref: ${ $ref } ` ) ;
243
+ }
244
+
245
+ const type = safeType . value ;
246
+
247
+ const io = getIOName ( type ) ;
248
+ const isRecursive = rootName === type || rootName === io ;
249
+ const definitionFilePath = refFileName . isSome ( )
250
+ ? getRelativeOutRefPath ( cwd , defBlock . value , refFileName . value , type )
251
+ : getRelativeRefPath ( cwd , defBlock . value , type ) ;
252
+
253
+ return serializedType (
254
+ type ,
255
+ io ,
256
+ isRecursive
257
+ ? EMPTY_DEPENDENCIES
258
+ : [ dependency ( type , definitionFilePath ) , dependency ( io , definitionFilePath ) ] ,
259
+ [ type ] ,
260
+ ) ;
237
261
}
238
262
239
- const type = safeType . value ;
240
-
241
- const io = getIOName ( type ) ;
242
- const isRecursive = rootName === type || rootName === io ;
243
- const definitionFilePath = refFileName . isSome ( )
244
- ? getRelativeOutRefPath ( cwd , defBlock . value , refFileName . value , type )
245
- : getRelativeRefPath ( cwd , defBlock . value , type ) ;
263
+ const results = schema . allOf . map ( item => serializeSchemaObject ( item , rootName , cwd ) ) ;
264
+ const types = results . map ( item => item . type ) ;
265
+ const ios = results . map ( item => item . io ) ;
266
+ const dependencies = fold ( monoidDependencies ) ( results . map ( item => item . dependencies ) ) ;
267
+ const refs = fold ( monoidRefs ) ( results . map ( item => item . refs ) ) ;
246
268
247
269
return serializedType (
248
- type ,
249
- io ,
250
- isRecursive
251
- ? EMPTY_DEPENDENCIES
252
- : [ dependency ( type , definitionFilePath ) , dependency ( io , definitionFilePath ) ] ,
253
- [ type ] ,
270
+ intercalate ( monoidString , array ) ( ' & ' , types ) ,
271
+ `intersection([${ intercalate ( monoidString , array ) ( ', ' , ios ) } ])` ,
272
+ [ dependency ( 'intersection' , 'io-ts' ) , ...dependencies ] ,
273
+ refs ,
254
274
) ;
255
275
}
256
276
case 'string' : {
@@ -607,7 +627,7 @@ const getIOName = (name: string): string => `${name}IO`;
607
627
const getOperationName = ( operation : TOperationObject , httpMethod : string ) =>
608
628
operation . operationId . getOrElse ( httpMethod ) ;
609
629
610
- const serializeDependencies = ( dependencies : TDepdendency [ ] ) : string =>
630
+ const serializeDependencies = ( dependencies : TDependency [ ] ) : string =>
611
631
collect ( groupBy ( dependencies , dependency => dependency . path ) , ( key , dependencies ) => {
612
632
const names = uniqString ( dependencies . toArray ( ) . map ( dependency => dependency . name ) ) ;
613
633
return `import { ${ names . join ( ',' ) } } from '${ dependencies . head . path } ';` ;
0 commit comments