@@ -140,6 +140,8 @@ export class DataSchemaCompiler {
140140
141141 private readonly compiledScriptCache : LRUCache < string , vm . Script > ;
142142
143+ private compileV8ContextCache : vm . Context ;
144+
143145 // FIXME: Is public only because of tests, should be private
144146 public compilePromise : any ;
145147
@@ -172,6 +174,7 @@ export class DataSchemaCompiler {
172174 this . workerPool = null ;
173175 this . compilerId = options . compilerId || 'default' ;
174176 this . compiledScriptCache = options . compiledScriptCache ;
177+ this . compileV8ContextCache = vm . createContext ( { } ) ;
175178 }
176179
177180 public compileObjects ( compileServices , objects , errorsReport : ErrorReporter ) {
@@ -563,7 +566,20 @@ export class DataSchemaCompiler {
563566 return this . compiledScriptCache . get ( cacheKey ) ! ;
564567 }
565568
566- const script = new vm . Script ( file . content , { filename : file . fileName } ) ;
569+ // As we run all data model files in the same context,
570+ // we need to wrap the code in an IIFE to avoid errors like:
571+ // Identifier 'xxx' has already been declared,
572+ // avoid polluting and modifying the global scope,
573+ // and to provide a controlled environment for the code execution.
574+ const wrappedCode = `
575+ (function(globals) {
576+ "use strict";
577+ const { view, cube, context, addExport, setExport, asyncModule, require, COMPILE_CONTEXT } = globals;
578+ ${ file . content }
579+ })(sandboxLocals);
580+ ` ;
581+
582+ const script = new vm . Script ( wrappedCode , { filename : file . fileName } ) ;
567583 this . compiledScriptCache . set ( cacheKey , script ) ;
568584 return script ;
569585 }
@@ -582,18 +598,17 @@ export class DataSchemaCompiler {
582598 try {
583599 const script = this . getJsScript ( file ) ;
584600
585- script . runInNewContext ( {
601+ const sandboxLocals = Object . freeze ( {
586602 view : ( name , cube ) => (
587603 ! cube ?
588604 this . cubeFactory ( { ...name , fileName : file . fileName , isView : true } ) :
589605 cubes . push ( { ...cube , name, fileName : file . fileName , isView : true } )
590606 ) ,
591- cube :
592- ( name , cube ) => (
593- ! cube ?
594- this . cubeFactory ( { ...name , fileName : file . fileName } ) :
595- cubes . push ( { ...cube , name, fileName : file . fileName } )
596- ) ,
607+ cube : ( name , cube ) => (
608+ ! cube ?
609+ this . cubeFactory ( { ...name , fileName : file . fileName } ) :
610+ cubes . push ( { ...cube , name, fileName : file . fileName } )
611+ ) ,
597612 context : ( name , context ) => contexts . push ( { ...context , name, fileName : file . fileName } ) ,
598613 addExport : ( obj ) => {
599614 exports [ file . fileName ] = exports [ file . fileName ] || { } ;
@@ -637,9 +652,15 @@ export class DataSchemaCompiler {
637652 }
638653 } ,
639654 COMPILE_CONTEXT : this . standalone ? this . standaloneCompileContextProxy ( ) : this . cloneCompileContextWithGetterAlias ( this . compileContext || { } ) ,
640- } , { filename : file . fileName , timeout : 15000 } ) ;
655+ } ) ;
656+
657+ this . compileV8ContextCache . sandboxLocals = sandboxLocals ;
658+
659+ script . runInContext ( this . compileV8ContextCache , { timeout : 15000 } ) ;
641660 } catch ( e ) {
642661 errorsReport . error ( e ) ;
662+ } finally {
663+ delete this . compileV8ContextCache . sandboxLocals ;
643664 }
644665 }
645666
0 commit comments