1
+ "use strict" ;
2
+
3
+ /* eslint-disable no-unsafe-finally */
4
+ const _ = require ( "lodash" ) ;
5
+ const axios = require ( "axios" ) ;
6
+ const {
7
+ blue,
8
+ red,
9
+ reset,
10
+ bold
11
+ } = require ( "../const/colors" ) ;
12
+
13
+ /**
14
+ * @class Api
15
+ * @description A class to interact with the remote API.
16
+ * @throws Will throw an error if the class is instantiated directly.
17
+ */
18
+ class Api {
19
+ #apiUrl;
20
+ #apiKey;
21
+ #apiKeyType;
22
+
23
+ /**
24
+ * @param {string } apiUrl - The API base url.
25
+ * @param {string } apiKey - The API key.
26
+ * @param {string } apiKeyType - The type of the API key. It should be 'openai' or 'pythagora'.
27
+ * @throws Will throw an error if called directly.
28
+ */
29
+ constructor ( apiUrl , apiKey , apiKeyType ) {
30
+ if ( ! apiKey ) {
31
+ console . log ( `${ bold + red } No API key found!${ reset } ` ) ;
32
+ console . log ( "Please run:" ) ;
33
+ console . log ( `${ bold + blue } npx pythagora --config --pythagora-api-key <YOUR_PYTHAGORA_API_KEY>${ reset } ` ) ;
34
+ console . log ( "or" ) ;
35
+ console . log ( `${ bold + blue } npx pythagora --config --openai-api-key <YOUR_OPENAI_API_KEY>${ reset } ` ) ;
36
+ console . log ( "You can get Pythagora API key here: https://mailchi.mp/f4f4d7270a7a/api-waitlist" ) ;
37
+ process . exit ( 0 ) ;
38
+ }
39
+ if ( ! apiUrl || ! apiKey ) {
40
+ throw new Error ( "Please, pass API url!" ) ;
41
+ }
42
+ if ( apiKeyType !== "openai" && apiKeyType !== "pythagora" ) {
43
+ throw new Error ( "API key type value must be openai or pythagora!" ) ;
44
+ }
45
+ this . #apiUrl = apiUrl ;
46
+ this . #apiKey = apiKey ;
47
+ this . #apiKeyType = apiKeyType ;
48
+ }
49
+
50
+ /**
51
+ * Prepare and set the options for the API request
52
+ */
53
+ setOptions ( {
54
+ path,
55
+ method,
56
+ headers
57
+ } ) {
58
+ const parsedUrl = new URL ( this . #apiUrl) ;
59
+ const options = {
60
+ protocol : parsedUrl . protocol . replace ( ":" , "" ) ,
61
+ hostname : parsedUrl . hostname ,
62
+ port : parsedUrl . port ,
63
+ path : path || "/" ,
64
+ method : method || "POST" ,
65
+ headers : headers || {
66
+ "Content-Type" : "application/json" ,
67
+ apikey : this . #apiKey,
68
+ apikeytype : this . #apiKeyType
69
+ }
70
+ } ;
71
+ if ( ! options . port ) delete options . port ;
72
+ return options ;
73
+ }
74
+
75
+ /**
76
+ * Make API request
77
+ */
78
+ async makeRequest ( data , options , customLogFunction ) {
79
+ let gptResponse = "" ;
80
+ const httpModule = options . protocol === "http" ? require ( "http" ) : require ( "https" ) ;
81
+ return new Promise ( ( resolve , reject ) => {
82
+ const req = httpModule . request ( _ . omit ( options , [ "protocol" ] ) , function ( res ) {
83
+ res . on ( "data" , chunk => {
84
+ try {
85
+ const stringified = chunk . toString ( ) ;
86
+ try {
87
+ const json = JSON . parse ( stringified ) ;
88
+ if ( json . error || json . message ) {
89
+ gptResponse = json ;
90
+ return ;
91
+ }
92
+ } catch ( e ) { }
93
+ gptResponse += stringified ;
94
+ if ( customLogFunction ) customLogFunction ( gptResponse ) ; else process . stdout . write ( stringified ) ;
95
+ } catch ( e ) { }
96
+ } ) ;
97
+ res . on ( "end" , async function ( ) {
98
+ process . stdout . write ( "\n" ) ;
99
+ if ( res . statusCode >= 400 ) return reject ( new Error ( `Response status code: ${ res . statusCode } . Error message: ${ gptResponse } ` ) ) ;
100
+ if ( gptResponse . error ) return reject ( new Error ( `Error: ${ gptResponse . error . message } . Code: ${ gptResponse . error . code } ` ) ) ;
101
+ if ( gptResponse . message ) return reject ( new Error ( `Error: ${ gptResponse . message } . Code: ${ gptResponse . code } ` ) ) ;
102
+ gptResponse = gptResponse . split ( "pythagora_end:" ) . pop ( ) ;
103
+ return resolve ( gptResponse ) ;
104
+ } ) ;
105
+ } ) ;
106
+ req . on ( "error" , e => {
107
+ console . error ( "problem with request:" + e . message ) ;
108
+ reject ( e ) ;
109
+ } ) ;
110
+ req . write ( data ) ;
111
+ req . end ( ) ;
112
+ } ) ;
113
+ }
114
+ async getUnitTests ( data , customLogFunction ) {
115
+ const options = this . setOptions ( {
116
+ path : "/api/generate-unit-tests"
117
+ } ) ;
118
+ let tests , error ;
119
+ try {
120
+ tests = await this . makeRequest ( JSON . stringify ( data ) , options , customLogFunction ) ;
121
+ } catch ( e ) {
122
+ error = e ;
123
+ } finally {
124
+ return {
125
+ tests,
126
+ error
127
+ } ;
128
+ }
129
+ }
130
+ async expandUnitTests ( data , customLogFunction ) {
131
+ const options = this . setOptions ( {
132
+ path : "/api/expand-unit-tests"
133
+ } ) ;
134
+ let tests , error ;
135
+ try {
136
+ tests = await this . makeRequest ( JSON . stringify ( data ) , options , customLogFunction ) ;
137
+ } catch ( e ) {
138
+ error = e ;
139
+ } finally {
140
+ return {
141
+ tests,
142
+ error
143
+ } ;
144
+ }
145
+ }
146
+ async getJestAuthFunction ( loginMongoQueriesArray , loginRequestBody , loginEndpointPath ) {
147
+ const options = this . setOptions ( {
148
+ path : "/api/generate-jest-auth"
149
+ } ) ;
150
+ return this . makeRequest ( JSON . stringify ( {
151
+ loginMongoQueriesArray,
152
+ loginRequestBody,
153
+ loginEndpointPath
154
+ } ) , options ) ;
155
+ }
156
+
157
+ /**
158
+ * Generate jest test
159
+ */
160
+ async getJestTest ( test ) {
161
+ const options = this . setOptions ( {
162
+ path : "/api/generate-jest-test"
163
+ } ) ;
164
+ return this . makeRequest ( JSON . stringify ( test ) , options ) ;
165
+ }
166
+
167
+ /**
168
+ * Generate jest test name
169
+ */
170
+ async getJestTestName ( test , usedNames ) {
171
+ const options = this . setOptions ( {
172
+ path : "/api/generate-jest-test-name"
173
+ } ) ;
174
+ return this . makeRequest ( JSON . stringify ( {
175
+ test
176
+ } ) , options ) ;
177
+ }
178
+
179
+ /**
180
+ * Check if the test is eligible for export
181
+ */
182
+ async isEligibleForExport ( test ) {
183
+ try {
184
+ const options = this . setOptions ( {
185
+ path : "/api/check-if-eligible"
186
+ } ) ;
187
+ const response = await axios . post ( `${ options . protocol } ://${ options . hostname } ${ options . port ? ":" + options . port : "" } ${ options . path } ` , JSON . stringify ( {
188
+ test
189
+ } ) , {
190
+ headers : options . headers
191
+ } ) ;
192
+ return response . data ;
193
+ } catch ( error ) {
194
+ console . log ( error ) ;
195
+ return false ;
196
+ }
197
+ }
198
+ }
199
+ module . exports = Api ;
0 commit comments