11import vm from 'vm' ;
22import fs from 'fs' ;
3+ import os from 'os' ;
34import path from 'path' ;
45import syntaxCheck from 'syntax-error' ;
56import { parse } from '@babel/parser' ;
@@ -20,6 +21,20 @@ const moduleFileCache = {};
2021
2122const JINJA_SYNTAX = / { % | % } | { { | } } / ig;
2223
24+ const getThreadsCount = ( ) => {
25+ const envThreads = getEnv ( 'transpilationWorkerThreadsCount' ) ;
26+ if ( envThreads > 0 ) {
27+ return envThreads ;
28+ }
29+
30+ const cpuCount = os . cpus ( ) ?. length ;
31+ if ( cpuCount ) {
32+ return Math . max ( 1 , cpuCount - 1 ) ;
33+ }
34+
35+ return 3 ; // Default (like the workerpool do)
36+ } ;
37+
2338export class DataSchemaCompiler {
2439 constructor ( repository , options = { } ) {
2540 this . repository = repository ;
@@ -98,6 +113,7 @@ export class DataSchemaCompiler {
98113
99114 const transpilationWorkerThreads = getEnv ( 'transpilationWorkerThreads' ) ;
100115 const transpilationNative = getEnv ( 'transpilationNative' ) ;
116+ const transpilationNativeThreadsCount = getThreadsCount ( ) ;
101117 const { compilerId } = this ;
102118
103119 if ( ! transpilationNative && transpilationWorkerThreads ) {
@@ -149,7 +165,26 @@ export class DataSchemaCompiler {
149165
150166 await this . transpileJsFile ( dummyFile , errorsReport , { cubeNames, cubeSymbols, transpilerNames, contextSymbols : CONTEXT_SYMBOLS , compilerId, stage } ) ;
151167
152- results = await Promise . all ( toCompile . map ( f => this . transpileFile ( f , errorsReport , { transpilerNames, compilerId } ) ) ) ;
168+ const nonJsFilesTasks = toCompile . filter ( file => ! file . fileName . endsWith ( '.js' ) )
169+ . map ( f => this . transpileFile ( f , errorsReport , { transpilerNames, compilerId } ) ) ;
170+
171+ const jsFiles = toCompile . filter ( file => file . fileName . endsWith ( '.js' ) ) ;
172+ let jsChunks ;
173+ if ( jsFiles . length < transpilationNativeThreadsCount * transpilationNativeThreadsCount ) {
174+ jsChunks = [ jsFiles ] ;
175+ } else {
176+ const baseSize = Math . floor ( jsFiles . length / transpilationNativeThreadsCount ) ;
177+ jsChunks = [ ] ;
178+ for ( let i = 0 ; i < transpilationNativeThreadsCount ; i ++ ) {
179+ // For the last part, we take the remaining files so we don't lose the extra ones.
180+ const start = i * baseSize ;
181+ const end = ( i === transpilationNativeThreadsCount - 1 ) ? jsFiles . length : start + baseSize ;
182+ jsChunks . push ( jsFiles . slice ( start , end ) ) ;
183+ }
184+ }
185+ const JsFilesTasks = jsChunks . map ( chunk => this . transpileJsFilesBulk ( chunk , errorsReport , { transpilerNames, compilerId } ) ) ;
186+
187+ results = ( await Promise . all ( [ ...nonJsFilesTasks , ...JsFilesTasks ] ) ) . flat ( ) ;
153188 } else if ( transpilationWorkerThreads ) {
154189 results = await Promise . all ( toCompile . map ( f => this . transpileFile ( f , errorsReport , { cubeNames, cubeSymbols, transpilerNames } ) ) ) ;
155190 } else {
@@ -229,6 +264,44 @@ export class DataSchemaCompiler {
229264 }
230265 }
231266
267+ /**
268+ * Right now it is used only for transpilation in native,
269+ * so no checks for transpilation type inside this method
270+ */
271+ async transpileJsFilesBulk ( files , errorsReport , { cubeNames, cubeSymbols, contextSymbols, transpilerNames, compilerId, stage } ) {
272+ // for bulk processing this data may be optimized even more by passing transpilerNames, compilerId only once for a bulk
273+ // but this requires more complex logic to be implemented in the native side.
274+ // And comparing to the file content sizes, a few bytes of JSON data is not a big deal here
275+ const reqDataArr = files . map ( file => ( {
276+ fileName : file . fileName ,
277+ fileContent : file . content ,
278+ transpilers : transpilerNames ,
279+ compilerId,
280+ ...( cubeNames && {
281+ metaData : {
282+ cubeNames,
283+ cubeSymbols,
284+ contextSymbols,
285+ stage
286+ } ,
287+ } ) ,
288+ } ) ) ;
289+ const res = await transpileJs ( reqDataArr ) ;
290+
291+ return files . map ( ( file , index ) => {
292+ errorsReport . inFile ( file ) ;
293+ if ( ! res [ index ] ) { // This should not happen in theory but just to be safe
294+ errorsReport . error ( `No transpilation result received for the file ${ file . fileName } .` ) ;
295+ return undefined ;
296+ }
297+ errorsReport . addErrors ( res [ index ] . errors ) ;
298+ errorsReport . addWarnings ( res [ index ] . warnings ) ;
299+ errorsReport . exitFile ( ) ;
300+
301+ return { ...file , content : res [ index ] . code } ;
302+ } ) ;
303+ }
304+
232305 async transpileJsFile ( file , errorsReport , { cubeNames, cubeSymbols, contextSymbols, transpilerNames, compilerId, stage } ) {
233306 try {
234307 if ( getEnv ( 'transpilationNative' ) ) {
0 commit comments