@@ -4,11 +4,10 @@ import path from 'path'
44import { argvs , sanitizePackageName , exchangeArgv , execSync , cp , capitalize , regexAll } from './utils' ;
55
66import { fileURLToPath } from 'url' ;
7+ // @ts -expect-error
78const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) ) ;
89
910
10-
11-
1211class build {
1312
1413 language :string = 'python' ;
@@ -18,12 +17,11 @@ class build {
1817 destinationFolder :string ;
1918 downloadAndDelete :boolean ;
2019
21- constructor ( exchange : string , downloadAndDelete : boolean ) {
20+ constructor ( exchange : string ) {
2221 this . exchange = exchange ;
2322 this . sourceFolder = __dirname + `/ccxt/` ;
2423 this . destinationFolder = __dirname + `/../${ exchange } /ccxt/` ;
25- this . downloadAndDelete = downloadAndDelete ;
26- this . init ( exchange ) ;
24+ this . downloadAndDelete = ! argvs . includes ( '--nodownload' ) ;
2725 }
2826
2927 async downloadCcxtRepo ( ) {
@@ -139,54 +137,60 @@ class build {
139137 fs . writeFileSync ( __dirname + '/../meta.json' , stringified ) ;
140138 }
141139
142- replaceGlobalRegexes ( text : string , array : any [ ] ) {
140+ replaceGlobalRegexes ( text : string , array : any [ ] = [ ] ) {
143141 let newText = text ;
144142 newText = regexAll ( newText , [
145143 [ '__exchangeName__' , this . exchange ] ,
146144 [ '__ExchangeName__' , capitalize ( this . exchange ) ] ,
147145 ] ) ;
148- const otherStrings = {
146+ const defaults : any = {
149147 '__LINK_TO_OFFICIAL_EXCHANGE_DOCS__' : 'https://ccxt.com' ,
150- '__PYTHON_PACKAGE_NAME__' : undefined ,
151148 '__EXAMPLE_SYMBOL__' : 'BTC/USDC' ,
152149 } ;
153150 const exchangeConfig = this . globalConfigs [ 'exchanges' ] [ this . exchange ] ;
154- for ( const key in otherStrings ) {
155- const defaultValue = otherStrings [ key ] ;
156- let value = exchangeConfig [ key ] || defaultValue ; // at first, read from config, if not, use default
151+ for ( const key in defaults ) {
152+ const defaultValue = defaults [ key ] ;
153+ let value = exchangeConfig [ key ] || defaultValue ; // use default if value not set
157154 newText = newText . replace ( new RegExp ( `${ key } ` , 'g' ) , value ) ;
158155 }
159- const sanitized = sanitizePackageName ( exchangeConfig [ '__PYTHON_PACKAGE_NAME__' ] ) ;
160- newText = newText . replace ( new RegExp ( `__PYTHON_PACKAGE_KEY__` , 'g' ) , sanitized ) ;
156+ // newText = newText.replace(/__PYTHON_PACKAGE_KEY__/g, sanitizePackageName (exchangeConfig['__PYTHON_PACKAGE_NAME__']));
161157 return newText ;
162158 }
163159
160+ commonContentReplace ( filePath : string ) {
161+ let fileContent = fs . readFileSync ( filePath , 'utf8' ) ;
162+ fileContent = this . replaceGlobalRegexes ( fileContent ) ;
163+ fs . writeFileSync ( filePath , fileContent ) ;
164+ }
165+
164166 generateExamples ( ) {
165167 const destinationDir = __dirname + `/../examples/` ;
166168 cp ( __dirname + '/templates/examples/' , destinationDir ) ;
167169 // iterate through files and make replacements
168170 const files = fs . readdirSync ( destinationDir ) ;
169171 for ( const file of files ) {
170- const filePath = destinationDir + file ;
171- let fileContent = fs . readFileSync ( filePath , 'utf8' ) ;
172- fileContent = this . replaceGlobalRegexes ( fileContent , [ ] ) ;
173- fs . writeFileSync ( filePath , fileContent ) ;
172+ this . commonContentReplace ( destinationDir + file ) ;
174173 }
175174 }
176175
177176 generateReadme ( ) {
178- const destinationDir = __dirname + `/../README.md` ;
179- cp ( __dirname + '/templates/README.md' , destinationDir ) ;
180- let fileContent = fs . readFileSync ( destinationDir , 'utf8' ) ;
181- fileContent = this . replaceGlobalRegexes ( fileContent , [ ] ) ;
182- fs . writeFileSync ( destinationDir , fileContent ) ;
177+ const target = __dirname + `/../README.md` ;
178+ cp ( __dirname + '/templates/README.md' , target ) ;
179+ this . commonContentReplace ( target ) ;
180+ this . updateReadmeWithMethods ( )
183181 }
184182
185- async init ( exchange :string ) {
183+ generatePyprojectToml ( ) {
184+ const target = __dirname + `/../pyproject.toml` ;
185+ cp ( __dirname + '/templates/pyproject.toml' , target ) ;
186+ this . commonContentReplace ( target ) ;
187+ }
188+
189+ async init ( ) {
186190 if ( this . downloadAndDelete ) {
187191 await this . downloadCcxtRepo ( ) ;
188192 }
189- this . copyCcxtFiles ( exchange ) ;
193+ this . copyCcxtFiles ( this . exchange ) ;
190194 await this . setAllExchangesList ( ) ;
191195 await this . creataPackageInitFile ( ) ;
192196
@@ -204,12 +208,110 @@ class build {
204208 }
205209 console . log ( "Done!" ) ;
206210 }
211+
212+
213+
214+ sortMethods ( methods : string [ ] ) {
215+ return methods . sort ( ( a , b ) => {
216+ const aPriority = a . startsWith ( 'fetch' ) || a . startsWith ( 'create' ) ? 0 : 1 ;
217+ const bPriority = b . startsWith ( 'fetch' ) || b . startsWith ( 'create' ) ? 0 : 1 ;
218+ return aPriority - bPriority || a . localeCompare ( b ) ;
219+ } ) ;
220+ }
221+
222+
223+ updateReadme ( methods : string [ ] , rawMethods : string [ ] , wsMethods : string [ ] , readmePath : string ) {
224+ let readmeContent = fs . readFileSync ( readmePath , 'utf8' ) ;
225+
226+ const methodsFormatted = methods . map ( method => `- \`${ method } \`` ) . join ( '\n' ) ;
227+ const rawMethodsFormatted = rawMethods . map ( method => `- \`${ method } \`` ) . join ( '\n' ) ;
228+ const wsMethodsFormatted = wsMethods . map ( method => `- \`${ method } \`` ) . join ( '\n' ) ;
229+
230+ const newMethodsSection = `### REST Unified\n\n${ methodsFormatted } \n` ;
231+
232+ const newWsMethodsSection = `### WS Unified\n\n${ wsMethodsFormatted } \n` ;
233+
234+ const newRawMethodsSection = `### REST Raw\n\n${ rawMethodsFormatted } \n` ;
235+
236+ // Replace the existing #Methods section
237+ const regex = / # # # R E S T U n i f i e d \n [ \s \S ] * ?(? = \n # | $ ) / ;
238+ if ( regex . test ( readmeContent ) ) {
239+ readmeContent = readmeContent . replace ( regex , newMethodsSection ) ;
240+ } else {
241+ readmeContent += `\n${ newMethodsSection } ` ;
242+ }
243+
244+ // handleRestRaw
245+ const rawMethodRegex = / # # # R E S T R a w \n [ \s \S ] * ?(? = \n # | $ ) /
246+ if ( rawMethodRegex . test ( readmeContent ) ) {
247+ readmeContent = readmeContent . replace ( rawMethodRegex , newRawMethodsSection ) ;
248+ } else {
249+ readmeContent += `\n${ newRawMethodsSection } ` ;
250+ }
251+
252+ // handleWs
253+ const wsRegex = / # # # W S U n i f i e d \n [ \s \S ] * ?(? = \n # | $ ) / ;
254+ if ( wsRegex . test ( readmeContent ) ) {
255+ readmeContent = readmeContent . replace ( wsRegex , newWsMethodsSection ) ;
256+ } else {
257+ readmeContent += `\n${ newWsMethodsSection } ` ;
258+ }
259+
260+ fs . writeFileSync ( readmePath , readmeContent , 'utf8' ) ;
261+ }
262+
263+ async updateReadmeWithMethods ( ) {
264+ const filePath = this . destinationFolder + '/' + this . exchange + '.py' ;
265+ const wsFilePath = this . destinationFolder + '/pro/' + this . exchange + '.py' ;
266+ const abstractFile = this . destinationFolder + '/abstract/' + this . exchange + '.py' ;
267+ const readme = __dirname + '/../README.md' ;
268+
269+
270+ const content = fs . readFileSync ( filePath , 'utf8' ) ;
271+ const wsContent = fs . readFileSync ( wsFilePath , 'utf8' ) ;
272+ const abstractContent = fs . readFileSync ( abstractFile , 'utf8' ) ;
273+ const methodRegex = / d e f \s + ( [ a - z A - Z _ ] [ a - z A - Z 0 - 9 _ ] * ) \( ( [ ^ ) ] * ) \) / g;
274+ const abstractRegex = / \s + ( \w + ) \s = \s \w + \s = \s / g
275+ let restMethods : string [ ] = [ ] ;
276+ let wsMethods : string [ ] = [ ] ;
277+ let rawMethods : string [ ] = [ ] ;
278+ let match ;
279+
280+ while ( ( match = methodRegex . exec ( content ) ) !== null ) {
281+ const name = match [ 1 ] ;
282+ if ( name . startsWith ( 'parse' ) || name . startsWith ( 'sign' ) || name . startsWith ( 'handle' ) || name . startsWith ( 'load' ) ) {
283+ continue ;
284+ }
285+ restMethods . push ( `${ name } (${ match [ 2 ] } )` ) ;
286+ }
287+
288+ while ( ( match = methodRegex . exec ( wsContent ) ) !== null ) {
289+ const name = match [ 1 ] ;
290+ if ( name . startsWith ( 'handle' ) || name . startsWith ( 'parse' ) || name . startsWith ( 'request' ) || name . startsWith ( 'ping' ) ) {
291+ continue ;
292+ }
293+ wsMethods . push ( `${ name } (${ match [ 2 ] } )` ) ;
294+ }
295+
296+ while ( ( match = abstractRegex . exec ( abstractContent ) ) !== null ) {
297+ const name = match [ 1 ] ;
298+ rawMethods . push ( `${ name } (request)` ) ;
299+ }
300+
301+
302+ // console.log(this.sortMethods(re))
303+ this . updateReadme ( this . sortMethods ( restMethods ) , rawMethods , wsMethods , readme ) ;
304+ return restMethods ;
305+ }
207306}
208307
209308
210309// -------------------------------------------------------------------------------- //
211310
212311
213-
214- const donwloadAndDelete = ! argvs . includes ( '--nodownload' ) ;
215- new build ( exchangeArgv , donwloadAndDelete ) ;
312+ const builder = new build ( exchangeArgv ) ;
313+ if ( argvs [ 1 ] === '--methods' ) {
314+ builder . updateReadmeWithMethods ( )
315+ } else {
316+ builder . init ( )
317+ }
0 commit comments