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,43 +212,61 @@ 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 parts = fromNullable ( $ref . match ( / ^ ( ( .+ ) \/ ( .+ ) \. ( .+ ) ) ? # \/ ( .+ ) \/ ( .+ ) $ / ) ) ;
226
-
227
- const defBlock = parts . mapNullable ( parts => parts [ 5 ] ) ;
228
- const refFileName = parts . mapNullable ( parts => parts [ 3 ] ) ;
229
- const safeType = parts . mapNullable ( parts => parts [ 6 ] ) ;
230
-
231
- if ( safeType . isNone ( ) || defBlock . isNone ( ) ) {
232
- throw new Error ( `Invalid $ref: ${ $ref } ` ) ;
229
+ if ( is$ref ( schema ) ) {
230
+ const $ref = schema . $ref ;
231
+ const parts = fromNullable ( $ref . match ( / ^ ( ( .+ ) \/ ( .+ ) \. ( .+ ) ) ? # \/ ( .+ ) \/ ( .+ ) $ / ) ) ;
232
+
233
+ const defBlock = parts . mapNullable ( parts => parts [ 5 ] ) ;
234
+ const refFileName = parts . mapNullable ( parts => parts [ 3 ] ) ;
235
+ const safeType = parts . mapNullable ( parts => parts [ 6 ] ) ;
236
+
237
+ if ( safeType . isNone ( ) || defBlock . isNone ( ) ) {
238
+ throw new Error ( `Invalid $ref: ${ $ref } ` ) ;
239
+ }
240
+
241
+ const type = safeType . value ;
242
+
243
+ const io = getIOName ( type ) ;
244
+ const isRecursive = rootName === type || rootName === io ;
245
+ const definitionFilePath = refFileName . isSome ( )
246
+ ? getRelativeOutRefPath ( cwd , defBlock . value , refFileName . value , type )
247
+ : getRelativeRefPath ( cwd , defBlock . value , type ) ;
248
+
249
+ return serializedType (
250
+ type ,
251
+ io ,
252
+ isRecursive
253
+ ? EMPTY_DEPENDENCIES
254
+ : [ dependency ( type , definitionFilePath ) , dependency ( io , definitionFilePath ) ] ,
255
+ [ type ] ,
256
+ ) ;
233
257
}
234
258
235
- const type = safeType . value ;
236
-
237
- const io = getIOName ( type ) ;
238
- const isRecursive = rootName === type || rootName === io ;
239
- const definitionFilePath = refFileName . isSome ( )
240
- ? getRelativeOutRefPath ( cwd , defBlock . value , refFileName . value , type )
241
- : getRelativeRefPath ( cwd , defBlock . value , type ) ;
259
+ const results = schema . allOf . map ( item => serializeSchemaObject ( item , rootName , cwd ) ) ;
260
+ const types = results . map ( item => item . type ) ;
261
+ const ios = results . map ( item => item . io ) ;
262
+ const dependencies = fold ( monoidDependencies ) ( results . map ( item => item . dependencies ) ) ;
263
+ const refs = fold ( monoidRefs ) ( results . map ( item => item . refs ) ) ;
242
264
243
265
return serializedType (
244
- type ,
245
- io ,
246
- isRecursive
247
- ? EMPTY_DEPENDENCIES
248
- : [ dependency ( type , definitionFilePath ) , dependency ( io , definitionFilePath ) ] ,
249
- [ type ] ,
266
+ intercalate ( monoidString , array ) ( ' & ' , types ) ,
267
+ `intersection([${ intercalate ( monoidString , array ) ( ', ' , ios ) } ])` ,
268
+ [ dependency ( 'intersection' , 'io-ts' ) , ...dependencies ] ,
269
+ refs ,
250
270
) ;
251
271
}
252
272
case 'string' : {
@@ -603,7 +623,7 @@ const getIOName = (name: string): string => `${name}IO`;
603
623
const getOperationName = ( operation : TOperationObject , httpMethod : string ) =>
604
624
operation . operationId . getOrElse ( httpMethod ) ;
605
625
606
- const serializeDependencies = ( dependencies : TDepdendency [ ] ) : string =>
626
+ const serializeDependencies = ( dependencies : TDependency [ ] ) : string =>
607
627
collect ( groupBy ( dependencies , dependency => dependency . path ) , ( key , dependencies ) => {
608
628
const names = uniqString ( dependencies . toArray ( ) . map ( dependency => dependency . name ) ) ;
609
629
return `import { ${ names . join ( ',' ) } } from '${ dependencies . head . path } ';` ;
0 commit comments