@@ -3,9 +3,143 @@ import fsp from 'fs/promises';
3
3
import SwaggerParser from '@apidevtools/swagger-parser' ;
4
4
import type { OpenAPIV3 } from 'openapi-types' ;
5
5
6
- import { removeObjectName , walk } from '../../utils' ;
6
+ import { removeEnumType , removeObjectName , walk } from '../../utils' ;
7
+
8
+ import type {
9
+ CTS ,
10
+ CTSBlock ,
11
+ ParametersWithDataType ,
12
+ RequestCTS ,
13
+ RequestCTSOutput ,
14
+ } from './types' ;
15
+
16
+ /**
17
+ * Provide the `key` and `is*` params to apply custom logic in templates
18
+ * include the `-last` param to join with comma in mustache.
19
+ */
20
+ function transformParam ( {
21
+ key = '$root' ,
22
+ value,
23
+ last = true ,
24
+ testName,
25
+ parent,
26
+ suffix = 0 ,
27
+ } : {
28
+ key ?: string ;
29
+ value : any ;
30
+ last ?: boolean ;
31
+ testName : string ;
32
+ parent ?: string ;
33
+ suffix ?: number ;
34
+ } ) : ParametersWithDataType | ParametersWithDataType [ ] {
35
+ const isDate = key === 'endAt' ;
36
+ const isArray = Array . isArray ( value ) ;
37
+ let isObject = typeof value === 'object' && ! isArray ;
38
+ const isEnum = isObject && '$enumType' in value ;
39
+ const isString = typeof value === 'string' && ! isDate ;
40
+ const isBoolean = typeof value === 'boolean' ;
41
+ const isInteger = Number . isInteger ( value ) ;
42
+ const isDouble = typeof value === 'number' && ! isInteger ;
43
+ const objectName : string | undefined = ( value as any ) . $objectName ;
44
+ const isFreeFormObject = objectName === 'Object' ;
45
+
46
+ if ( isEnum ) {
47
+ isObject = false ;
48
+ }
49
+
50
+ const isTypes = {
51
+ isArray,
52
+ isObject : isObject && ! isFreeFormObject ,
53
+ isFreeFormObject,
54
+ isEnum,
55
+ isString,
56
+ isBoolean,
57
+ isInteger,
58
+ isDouble,
59
+ } ;
60
+
61
+ const isRoot = key === '$root' ;
62
+
63
+ let out = value ;
64
+ if ( isEnum ) {
65
+ out = { enumType : value . $enumType , value : value . value } ;
66
+ } else if ( isObject ) {
67
+ // recursive on every key:value
68
+ out = Object . entries ( value )
69
+ . filter ( ( [ prop ] ) => prop !== '$objectName' )
70
+ . map ( ( [ inKey , inValue ] , i , arr ) =>
71
+ transformParam ( {
72
+ key : inKey ,
73
+ value : inValue ,
74
+ last : i === arr . length - 1 ,
75
+ testName,
76
+ parent : isRoot ? 'param' : key ,
77
+ suffix : suffix + 1 ,
78
+ } )
79
+ ) ;
80
+
81
+ // Special case for root
82
+ if ( isRoot ) {
83
+ if ( objectName ) {
84
+ return {
85
+ key : 'param' ,
86
+ value : out ,
87
+ objectName,
88
+ suffix,
89
+ parentSuffix : suffix ,
90
+ ...isTypes ,
91
+ '-last' : true ,
92
+ } ;
93
+ }
94
+ return out ;
95
+ }
96
+
97
+ if ( ! objectName ) {
98
+ // throw new Error(`Object ${key} missing property $objectName in test ${testName}`);
99
+ // eslint-disable-next-line no-console
100
+ console . log (
101
+ `Object ${ key } missing property $objectName in test ${ testName } `
102
+ ) ;
103
+ }
104
+ } else if ( isArray ) {
105
+ // recursive on all value
106
+ out = value . map ( ( v , i ) =>
107
+ transformParam ( {
108
+ key : `${ key } Param${ i } ` ,
109
+ value : v ,
110
+ last : i === value . length - 1 ,
111
+ testName,
112
+ parent : key ,
113
+ suffix : suffix + 1 ,
114
+ } )
115
+ ) ;
116
+ }
117
+
118
+ return {
119
+ key,
120
+ value : out ,
121
+ objectName,
122
+ parent,
123
+ suffix,
124
+ parentSuffix : suffix - 1 ,
125
+ ...isTypes ,
126
+ '-last' : last ,
127
+ } ;
128
+ }
7
129
8
- import type { CTS , CTSBlock , Tests } from './types' ;
130
+ function createParamWithDataType ( {
131
+ parameters,
132
+ testName,
133
+ } : {
134
+ parameters : Record < string , any > ;
135
+ testName : string ;
136
+ } ) : ParametersWithDataType [ ] {
137
+ const transformed = transformParam ( { value : parameters , testName } ) ;
138
+ if ( Array . isArray ( transformed ) ) {
139
+ return transformed ;
140
+ }
141
+ return [ transformed ] ;
142
+ }
9
143
10
144
async function loadRequestsCTS ( client : string ) : Promise < CTSBlock [ ] > {
11
145
// load the list of operations from the spec
@@ -31,67 +165,57 @@ async function loadRequestsCTS(client: string): Promise<CTSBlock[]> {
31
165
throw new Error ( `cannot read empty file ${ fileName } - ${ client } client` ) ;
32
166
}
33
167
34
- const tests : Tests [ ] = JSON . parse ( fileContent ) ;
168
+ const tests : RequestCTS [ ] = JSON . parse ( fileContent ) ;
35
169
36
170
// check test validity against spec
37
171
if ( ! operations . includes ( fileName ) ) {
38
172
throw new Error ( `cannot find ${ fileName } for the ${ client } client` ) ;
39
173
}
40
174
175
+ const testsOutput : RequestCTSOutput [ ] = [ ] ;
176
+ let testIndex = 0 ;
41
177
for ( const test of tests ) {
42
- if ( test . testName === undefined ) {
43
- test . testName = test . method ;
44
- }
178
+ const testOutput = test as RequestCTSOutput ;
179
+ testOutput . testName = test . testName || test . method ;
180
+ testOutput . testIndex = testIndex ++ ;
45
181
46
182
// stringify request.data too
47
- test . request . data = JSON . stringify ( test . request . data ) ;
48
- test . request . searchParams = JSON . stringify ( test . request . searchParams ) ;
49
-
50
- if ( Object . keys ( test . parameters ) . length === 0 ) {
51
- test . parameters = undefined ;
52
- test . parametersWithDataType = undefined ;
53
- test . hasParameters = false ;
54
-
55
- continue ;
56
- }
183
+ testOutput . request . data = JSON . stringify ( test . request . data ) ;
184
+ testOutput . request . searchParams = JSON . stringify (
185
+ test . request . searchParams
186
+ ) ;
57
187
58
188
if (
59
189
typeof test . parameters !== 'object' ||
60
190
Array . isArray ( test . parameters )
61
191
) {
62
- throw new Error ( `parameters of ${ test . testName } must be an object` ) ;
192
+ throw new Error (
193
+ `parameters of ${ testOutput . testName } must be an object`
194
+ ) ;
63
195
}
64
196
65
- // we stringify the param for mustache to render them properly
66
- // delete the object name recursively for now, but it could be use for `new $objectName(params)`
67
- removeObjectName ( test . parameters ) ;
68
-
69
- // Provide the `key` and `is*` params to apply custom logic in templates
70
- // include the `-last` param to join with comma in mustache
71
- test . parametersWithDataType = Object . entries ( test . parameters ) . map (
72
- ( [ key , value ] , i , arr ) => {
73
- const isDate = key === 'endAt' ;
74
- const isArray = Array . isArray ( value ) ;
75
-
76
- return {
77
- key,
78
- value : JSON . stringify ( value ) ,
79
- isString : typeof value === 'string' && isDate === false ,
80
- isObject : typeof value === 'object' && isArray === false ,
81
- isArray,
82
- isDate,
83
- '-last' : i === arr . length - 1 ,
84
- } ;
85
- }
86
- ) ;
87
-
88
- test . parameters = JSON . stringify ( test . parameters ) ;
89
- test . hasParameters = true ;
197
+ if ( Object . keys ( test . parameters ) . length === 0 ) {
198
+ testOutput . parameters = undefined ;
199
+ testOutput . parametersWithDataType = undefined ;
200
+ testOutput . hasParameters = false ;
201
+ } else {
202
+ testOutput . parametersWithDataType = createParamWithDataType ( {
203
+ parameters : test . parameters ,
204
+ testName : testOutput . testName ,
205
+ } ) ;
206
+
207
+ // we stringify the param for mustache to render them properly
208
+ testOutput . parameters = JSON . stringify (
209
+ removeEnumType ( removeObjectName ( test . parameters ) )
210
+ ) ;
211
+ testOutput . hasParameters = true ;
212
+ }
213
+ testsOutput . push ( testOutput ) ;
90
214
}
91
215
92
216
ctsClient . push ( {
93
217
operationId : fileName ,
94
- tests,
218
+ tests : testsOutput ,
95
219
} ) ;
96
220
}
97
221
0 commit comments