@jsreport/jsreport-core 3.5.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,7 @@
5
5
  */
6
6
  const path = require('path')
7
7
  const { Readable } = require('stream')
8
- const Reaper = require('reap2')
8
+ const Reaper = require('@jsreport/reap')
9
9
  const optionsLoad = require('./optionsLoad')
10
10
  const { createLogger, configureLogger, silentLogs } = require('./logger')
11
11
  const checkEntityName = require('./validateEntityName')
@@ -90,8 +90,8 @@ class MainReporter extends Reporter {
90
90
  return this
91
91
  }
92
92
 
93
- async extensionsLoad (opts) {
94
- const appliedConfigFile = await optionsLoad({
93
+ async extensionsLoad (_opts = {}) {
94
+ const [explicitOptions, appliedConfigFile] = await optionsLoad({
95
95
  defaults: this.defaults,
96
96
  options: this.options,
97
97
  validator: this.optionsValidator,
@@ -106,6 +106,8 @@ class MainReporter extends Reporter {
106
106
  silentLogs(this.logger)
107
107
  }
108
108
 
109
+ const { onConfigDetails, ...opts } = _opts
110
+
109
111
  this.logger.info(`Initializing jsreport (version: ${this.version}, configuration file: ${appliedConfigFile || 'none'}, nodejs: ${process.versions.node})`)
110
112
 
111
113
  await this.extensionsManager.load(opts)
@@ -130,6 +132,10 @@ class MainReporter extends Reporter {
130
132
  throw new Error(`options contain values that does not match the defined full root schema. ${rootOptionsValidation.fullErrorMessage}`)
131
133
  }
132
134
 
135
+ if (typeof onConfigDetails === 'function') {
136
+ onConfigDetails(explicitOptions)
137
+ }
138
+
133
139
  return this
134
140
  }
135
141
 
@@ -157,6 +163,7 @@ class MainReporter extends Reporter {
157
163
  */
158
164
  async init () {
159
165
  this.closing = this.closed = false
166
+
160
167
  if (this._initialized || this._initializing) {
161
168
  throw new Error('jsreport already initialized or just initializing. Make sure init is called only once')
162
169
  }
@@ -175,14 +182,22 @@ class MainReporter extends Reporter {
175
182
 
176
183
  try {
177
184
  this._registerLogMainAction()
178
- await this.extensionsLoad()
185
+
186
+ let explicitOptions
187
+
188
+ await this.extensionsLoad({
189
+ onConfigDetails: (_explicitOptions) => {
190
+ explicitOptions = _explicitOptions
191
+ }
192
+ })
179
193
 
180
194
  this.documentStore = DocumentStore(Object.assign({}, this.options, { logger: this.logger }), this.entityTypeValidator, this.encryption)
181
195
  documentStoreActions(this)
182
196
  this.blobStorage = BlobStorage(this, this.options)
183
197
  blobStorageActions(this)
184
198
  Templates(this)
185
- Profiler(this)
199
+
200
+ this._cleanProfileInRequest = Profiler(this)
186
201
 
187
202
  this.folders = Object.assign(this.folders, Folders(this))
188
203
 
@@ -200,6 +215,14 @@ class MainReporter extends Reporter {
200
215
 
201
216
  await this.extensionsManager.init()
202
217
 
218
+ if (this.options.trustUserCode) {
219
+ this.logger.info('Code sandboxing is disabled, users can potentially penetrate the local system if you allow code from external users to be part of your reports')
220
+ }
221
+
222
+ if (explicitOptions.trustUserCode == null && explicitOptions.allowLocalFilesAccess != null) {
223
+ this.logger.warn('options.allowLocalFilesAccess is deprecated, use options.trustUserCode instead')
224
+ }
225
+
203
226
  this.logger.info(`Using general timeout for rendering (reportTimeout: ${this.options.reportTimeout})`)
204
227
 
205
228
  if (this.options.store.provider === 'memory') {
@@ -450,11 +473,17 @@ class MainReporter extends Reporter {
450
473
  }, req)
451
474
 
452
475
  Object.assign(res, responseResult)
476
+
453
477
  await this.afterRenderListeners.fire(req, res)
478
+
454
479
  res.stream = Readable.from(res.content)
480
+
481
+ this._cleanProfileInRequest(req)
482
+
455
483
  return res
456
484
  } catch (err) {
457
485
  await this._handleRenderError(req, res, err)
486
+ this._cleanProfileInRequest(req)
458
487
  throw err
459
488
  } finally {
460
489
  if (worker && !workerAborted && !dontCloseProcessing) {
@@ -9,9 +9,10 @@ const LRU = require('lru-cache')
9
9
  const { nanoid } = require('nanoid')
10
10
 
11
11
  module.exports = (reporter) => {
12
- const cache = LRU(reporter.options.sandbox.cache || { max: 100 })
12
+ const templatesCache = LRU(reporter.options.sandbox.cache)
13
+ let systemHelpersCache
13
14
 
14
- reporter.templatingEngines = { cache }
15
+ reporter.templatingEngines = { cache: templatesCache }
15
16
 
16
17
  const executionFnParsedParamsMap = new Map()
17
18
  const executionAsyncResultsMap = new Map()
@@ -60,11 +61,44 @@ module.exports = (reporter) => {
60
61
  evaluate: async (executionInfo, entityInfo) => {
61
62
  return templatingEnginesEvaluate(false, executionInfo, entityInfo, req)
62
63
  },
64
+ waitForAsyncHelper: async (maybeAsyncContent) => {
65
+ if (
66
+ context.__executionId == null ||
67
+ !executionAsyncResultsMap.has(context.__executionId) ||
68
+ typeof maybeAsyncContent !== 'string'
69
+ ) {
70
+ return maybeAsyncContent
71
+ }
72
+
73
+ const asyncResultMap = executionAsyncResultsMap.get(context.__executionId)
74
+ const asyncHelperResultRegExp = /{#asyncHelperResult ([^{}]+)}/
75
+ let content = maybeAsyncContent
76
+ let matchResult
77
+
78
+ do {
79
+ if (matchResult != null) {
80
+ const matchedPart = matchResult[0]
81
+ const asyncResultId = matchResult[1]
82
+ const result = await asyncResultMap.get(asyncResultId)
83
+ content = `${content.slice(0, matchResult.index)}${result}${content.slice(matchResult.index + matchedPart.length)}`
84
+ }
85
+
86
+ matchResult = content.match(asyncHelperResultRegExp)
87
+ } while (matchResult != null)
88
+
89
+ return content
90
+ },
63
91
  waitForAsyncHelpers: async () => {
64
92
  if (context.__executionId != null && executionAsyncResultsMap.has(context.__executionId)) {
65
93
  const asyncResultMap = executionAsyncResultsMap.get(context.__executionId)
66
94
  return Promise.all([...asyncResultMap.keys()].map((k) => asyncResultMap.get(k)))
67
95
  }
96
+ },
97
+ createAsyncHelperResult: (v) => {
98
+ const asyncResultMap = executionAsyncResultsMap.get(context.__executionId)
99
+ const asyncResultId = nanoid(7)
100
+ asyncResultMap.set(asyncResultId, v)
101
+ return `{#asyncHelperResult ${asyncResultId}}`
68
102
  }
69
103
  }
70
104
  })
@@ -102,22 +136,49 @@ module.exports = (reporter) => {
102
136
  entityPath = await reporter.folders.resolveEntityPath(entity, entitySet, req)
103
137
  }
104
138
 
105
- const registerResults = await reporter.registerHelpersListeners.fire(req)
106
- const systemHelpers = []
139
+ const normalizedHelpers = `${helpers || ''}`
140
+ const executionFnParsedParamsKey = `entity:${entity.shortid || 'anonymous'}:helpers:${normalizedHelpers}`
107
141
 
108
- for (const result of registerResults) {
109
- if (result == null) {
110
- continue
142
+ const initFn = async (getTopLevelFunctions, compileScript) => {
143
+ if (systemHelpersCache != null) {
144
+ return systemHelpersCache
111
145
  }
112
146
 
113
- if (typeof result === 'string') {
114
- systemHelpers.push(result)
147
+ const registerResults = await reporter.registerHelpersListeners.fire()
148
+ const systemHelpers = []
149
+
150
+ for (const result of registerResults) {
151
+ if (result == null) {
152
+ continue
153
+ }
154
+
155
+ if (typeof result === 'string') {
156
+ systemHelpers.push(result)
157
+ }
115
158
  }
116
- }
117
159
 
118
- const systemHelpersStr = systemHelpers.join('\n')
119
- const joinedHelpers = systemHelpersStr + '\n' + (helpers || '')
120
- const executionFnParsedParamsKey = `entity:${entity.shortid || 'anonymous'}:helpers:${joinedHelpers}`
160
+ const systemHelpersStr = systemHelpers.join('\n')
161
+
162
+ const functionNames = getTopLevelFunctions(systemHelpersStr)
163
+
164
+ const exposeSystemHelpersCode = `for (const fName of ${JSON.stringify(functionNames)}) { this[fName] = __topLevelFunctions[fName] }`
165
+
166
+ // we sync the __topLevelFunctions with system helpers and expose it immediately to the global context
167
+ const userCode = `(async () => { ${systemHelpersStr};
168
+ __topLevelFunctions = {...__topLevelFunctions, ${functionNames.map(h => `"${h}": ${h}`).join(',')}}; ${exposeSystemHelpersCode}
169
+ })()`
170
+
171
+ const filename = 'system-helpers.js'
172
+ const script = compileScript(userCode, filename)
173
+
174
+ systemHelpersCache = {
175
+ filename,
176
+ source: systemHelpersStr,
177
+ script
178
+ }
179
+
180
+ return systemHelpersCache
181
+ }
121
182
 
122
183
  const executionFn = async ({ require, console, topLevelFunctions, context }) => {
123
184
  const asyncResultMap = new Map()
@@ -129,25 +190,30 @@ module.exports = (reporter) => {
129
190
 
130
191
  const key = `template:${content}:${engine.name}`
131
192
 
132
- if (!cache.has(key)) {
193
+ if (!templatesCache.has(key)) {
133
194
  try {
134
- cache.set(key, engine.compile(content, { require }))
195
+ templatesCache.set(key, engine.compile(content, { require }))
135
196
  } catch (e) {
136
197
  e.property = 'content'
137
198
  throw e
138
199
  }
139
200
  }
140
201
 
141
- const compiledTemplate = cache.get(key)
142
-
202
+ const compiledTemplate = templatesCache.get(key)
143
203
  const wrappedTopLevelFunctions = {}
144
204
 
145
205
  for (const h of Object.keys(topLevelFunctions)) {
146
- wrappedTopLevelFunctions[h] = wrapHelperForAsyncSupport(topLevelFunctions[h], asyncResultMap)
206
+ if (engine.getWrappingHelpersEnabled && engine.getWrappingHelpersEnabled(req) === false) {
207
+ wrappedTopLevelFunctions[h] = engine.wrapHelper(topLevelFunctions[h], { context })
208
+ } else {
209
+ wrappedTopLevelFunctions[h] = wrapHelperForAsyncSupport(topLevelFunctions[h], asyncResultMap)
210
+ }
147
211
  }
148
212
 
149
213
  let contentResult = await engine.execute(compiledTemplate, wrappedTopLevelFunctions, data, { require })
214
+
150
215
  const resolvedResultsMap = new Map()
216
+
151
217
  while (asyncResultMap.size > 0) {
152
218
  await Promise.all([...asyncResultMap.keys()].map(async (k) => {
153
219
  resolvedResultsMap.set(k, `${await asyncResultMap.get(k)}`)
@@ -178,25 +244,27 @@ module.exports = (reporter) => {
178
244
  return executionFn({ require, console, topLevelFunctions, context })
179
245
  } else {
180
246
  const awaiter = {}
247
+
181
248
  awaiter.promise = new Promise((resolve) => {
182
249
  awaiter.resolve = resolve
183
250
  })
251
+
184
252
  executionFnParsedParamsMap.get(req.context.id).set(executionFnParsedParamsKey, awaiter)
185
253
  }
186
254
 
187
255
  if (reporter.options.sandbox.cache && reporter.options.sandbox.cache.enabled === false) {
188
- cache.reset()
256
+ templatesCache.reset()
189
257
  }
190
258
 
191
259
  try {
192
260
  return await reporter.runInSandbox({
193
261
  context: {
194
- ...(engine.createContext ? engine.createContext() : {})
262
+ ...(engine.createContext ? engine.createContext(req) : {})
195
263
  },
196
- userCode: joinedHelpers,
264
+ userCode: normalizedHelpers,
265
+ initFn,
197
266
  executionFn,
198
267
  currentPath: entityPath,
199
- errorLineNumberOffset: systemHelpersStr.split('\n').length,
200
268
  onRequire: (moduleName, { context }) => {
201
269
  if (engine.onRequire) {
202
270
  return engine.onRequire(moduleName, { context })
@@ -4,7 +4,7 @@ const path = require('path')
4
4
  module.exports = (reporter) => {
5
5
  let helpersScript
6
6
 
7
- reporter.registerHelpersListeners.add('core-helpers', (req) => {
7
+ reporter.registerHelpersListeners.add('core-helpers', () => {
8
8
  return helpersScript
9
9
  })
10
10
 
@@ -12,11 +12,11 @@ module.exports = (reporter) => {
12
12
  helpersScript = await fs.readFile(path.join(__dirname, '../../static/helpers.js'), 'utf8')
13
13
  })
14
14
 
15
- reporter.extendProxy((proxy, req, { safeRequire }) => {
15
+ reporter.extendProxy((proxy, req, { sandboxRequire }) => {
16
16
  proxy.module = async (module) => {
17
- if (!reporter.options.allowLocalFilesAccess && reporter.options.sandbox.allowedModules !== '*') {
17
+ if (!reporter.options.trustUserCode && reporter.options.sandbox.allowedModules !== '*') {
18
18
  if (reporter.options.sandbox.allowedModules.indexOf(module) === -1) {
19
- throw reporter.createError(`require of module ${module} was rejected. Either set allowLocalFilesAccess=true or sandbox.allowLocalModules='*' or sandbox.allowLocalModules=['${module}'] `, { status: 400 })
19
+ throw reporter.createError(`require of module ${module} was rejected. Either set trustUserCode=true or sandbox.allowLocalModules='*' or sandbox.allowLocalModules=['${module}'] `, { status: 400 })
20
20
  }
21
21
  }
22
22
 
@@ -36,7 +36,10 @@ class Profiler {
36
36
  if (profilingInfo) {
37
37
  const batch = profilingInfo.batch
38
38
  profilingInfo.batch = []
39
- await this.reporter.executeMainAction('profile', batch, profilingInfo.req).catch((e) => this.reporter.logger.error(e, profilingInfo.req))
39
+
40
+ if (batch.length > 0) {
41
+ await this.reporter.executeMainAction('profile', batch, profilingInfo.req).catch((e) => this.reporter.logger.error(e, profilingInfo.req))
42
+ }
40
43
  }
41
44
  }
42
45
  }
@@ -72,7 +75,7 @@ class Profiler {
72
75
  let content = res.content
73
76
 
74
77
  if (content != null) {
75
- if (content.length > this.reporter.options.profiler.maxResponseSize) {
78
+ if (content.length > this.reporter.options.profiler.maxDiffSize) {
76
79
  content = {
77
80
  tooLarge: true
78
81
  }
@@ -97,7 +100,12 @@ class Profiler {
97
100
 
98
101
  const stringifiedReq = JSON.stringify({ template: req.template, data: req.data }, null, 2)
99
102
 
100
- m.req = { diff: createPatch('req', req.context.profiling.reqLastVal || '', stringifiedReq, 0) }
103
+ m.req = { }
104
+ if (stringifiedReq.length * 4 > this.reporter.options.profiler.maxDiffSize) {
105
+ m.req.tooLarge = true
106
+ } else {
107
+ m.req.diff = createPatch('req', req.context.profiling.reqLastVal || '', stringifiedReq, 0)
108
+ }
101
109
 
102
110
  req.context.profiling.resLastVal = (res.content == null || isbinaryfile(res.content) || content.tooLarge) ? null : res.content.toString()
103
111
  req.context.profiling.resMetaLastVal = stringifiedResMeta
@@ -153,7 +161,10 @@ class Profiler {
153
161
  const profilingInfo = this.profiledRequestsMap.get(req.context.rootId)
154
162
  if (profilingInfo) {
155
163
  this.profiledRequestsMap.delete(req.context.rootId)
156
- await this.reporter.executeMainAction('profile', profilingInfo.batch, req)
164
+
165
+ if (profilingInfo.batch.length > 0) {
166
+ await this.reporter.executeMainAction('profile', profilingInfo.batch, req)
167
+ }
157
168
  }
158
169
  }
159
170
  }
@@ -130,7 +130,7 @@ module.exports = (reporter) => {
130
130
  reporter.requestModulesCache.set(request.context.rootId, Object.create(null))
131
131
  }
132
132
 
133
- reporter.logger.info(`Starting rendering request ${request.context.reportCounter} (user: ${(request.context.user ? request.context.user.username : 'null')})`, request)
133
+ reporter.logger.info(`Starting rendering request ${request.context.reportCounter} (user: ${(request.context.user ? request.context.user.name : 'null')})`, request)
134
134
 
135
135
  // TODO
136
136
  /* if (reporter.entityTypeValidator.getSchema('TemplateType') != null) {
@@ -111,14 +111,14 @@ class WorkerReporter extends Reporter {
111
111
  this._proxyRegistrationFns.push(registrationFn)
112
112
  }
113
113
 
114
- createProxy ({ req, runInSandbox, context, getTopLevelFunctions, safeRequire }) {
114
+ createProxy ({ req, runInSandbox, context, getTopLevelFunctions, sandboxRequire }) {
115
115
  const proxyInstance = {}
116
116
  for (const fn of this._proxyRegistrationFns) {
117
117
  fn(proxyInstance, req, {
118
118
  runInSandbox,
119
119
  context,
120
120
  getTopLevelFunctions,
121
- safeRequire
121
+ sandboxRequire
122
122
  })
123
123
  }
124
124
  return proxyInstance
@@ -137,10 +137,11 @@ class WorkerReporter extends Reporter {
137
137
  manager,
138
138
  context,
139
139
  userCode,
140
+ initFn,
140
141
  executionFn,
142
+ currentPath,
141
143
  onRequire,
142
144
  propertiesConfig,
143
- currentPath,
144
145
  errorLineNumberOffset
145
146
  }, req) {
146
147
  // we flush before running code in sandbox because it can potentially
@@ -152,10 +153,11 @@ class WorkerReporter extends Reporter {
152
153
  manager,
153
154
  context,
154
155
  userCode,
156
+ initFn,
155
157
  executionFn,
158
+ currentPath,
156
159
  onRequire,
157
160
  propertiesConfig,
158
- currentPath,
159
161
  errorLineNumberOffset
160
162
  }, req)
161
163
  }
@@ -19,6 +19,7 @@ module.exports = (_sandbox, options = {}) => {
19
19
  propertiesConfig = {},
20
20
  globalModules = [],
21
21
  allowedModules = [],
22
+ safeExecution,
22
23
  requireMap
23
24
  } = options
24
25
 
@@ -65,7 +66,7 @@ module.exports = (_sandbox, options = {}) => {
65
66
  }
66
67
  }
67
68
 
68
- if (allowAllModules || allowedModules === '*') {
69
+ if (!safeExecution || allowAllModules || allowedModules === '*') {
69
70
  return doRequire(moduleName, requirePaths, modulesCache)
70
71
  }
71
72
 
@@ -111,14 +112,28 @@ module.exports = (_sandbox, options = {}) => {
111
112
  require: (m) => _require(m, { context: _sandbox })
112
113
  })
113
114
 
114
- const vm = new VM()
115
+ let safeVM
116
+ let vmSandbox
115
117
 
116
- // delete the vm.sandbox.global because it introduces json stringify issues
117
- // and we don't need such global in context
118
- delete vm.sandbox.global
118
+ if (safeExecution) {
119
+ safeVM = new VM()
119
120
 
120
- for (const name in sandbox) {
121
- vm.setGlobal(name, sandbox[name])
121
+ // delete the vm.sandbox.global because it introduces json stringify issues
122
+ // and we don't need such global in context
123
+ delete safeVM.sandbox.global
124
+
125
+ for (const name in sandbox) {
126
+ safeVM.setGlobal(name, sandbox[name])
127
+ }
128
+
129
+ vmSandbox = safeVM.sandbox
130
+ } else {
131
+ vmSandbox = originalVM.createContext(undefined)
132
+ vmSandbox.Buffer = Buffer
133
+
134
+ for (const name in sandbox) {
135
+ vmSandbox[name] = sandbox[name]
136
+ }
122
137
  }
123
138
 
124
139
  // processing top level props because getter/setter descriptors
@@ -127,49 +142,46 @@ module.exports = (_sandbox, options = {}) => {
127
142
  const currentConfig = propsConfig[key]
128
143
 
129
144
  if (currentConfig.root && currentConfig.root.sandboxReadOnly) {
130
- readOnlyProp(vm.sandbox, key, [], customProxies, { onlyTopLevel: true })
145
+ readOnlyProp(vmSandbox, key, [], customProxies, { onlyTopLevel: true })
131
146
  }
132
147
  })
133
148
 
134
149
  const sourceFilesInfo = new Map()
135
150
 
136
151
  return {
137
- sandbox: vm.sandbox,
152
+ sandbox: vmSandbox,
138
153
  console: _console,
139
154
  sourceFilesInfo,
155
+ compileScript: (code, filename) => {
156
+ return doCompileScript(code, filename, safeExecution)
157
+ },
140
158
  restore: () => {
141
- return restoreProperties(vm.sandbox, originalValues, proxiesInVM, customProxies)
159
+ return restoreProperties(vmSandbox, originalValues, proxiesInVM, customProxies)
142
160
  },
143
- safeRequire: (modulePath) => _require(modulePath, { context: _sandbox, allowAllModules: true }),
144
- run: async (code, { filename, errorLineNumberOffset = 0, source, entity, entitySet } = {}) => {
145
- const script = new VMScript(code, filename)
161
+ sandboxRequire: (modulePath) => _require(modulePath, { context: _sandbox, allowAllModules: true }),
162
+ run: async (codeOrScript, { filename, errorLineNumberOffset = 0, source, entity, entitySet } = {}) => {
163
+ let run
146
164
 
147
165
  if (filename != null && source != null) {
148
166
  sourceFilesInfo.set(filename, { filename, source, entity, entitySet, errorLineNumberOffset })
149
167
  }
150
168
 
151
- // NOTE: if we need to upgrade vm2 we will need to check the source of this function
152
- // in vm2 repo and see if we need to change this,
153
- // we needed to override this method because we want "displayErrors" to be true in order
154
- // to show nice error when the compile of a script fails
155
- script._compile = function (prefix, suffix) {
156
- return new originalVM.Script(prefix + this.getCompiledCode() + suffix, {
157
- __proto__: null,
158
- filename: this.filename,
159
- displayErrors: true,
160
- lineOffset: this.lineOffset,
161
- columnOffset: this.columnOffset,
162
- // THIS FN WAS TAKEN FROM vm2 source, nothing special here
163
- importModuleDynamically: () => {
164
- // We can't throw an error object here because since vm.Script doesn't store a context, we can't properly contextify that error object.
165
- // eslint-disable-next-line no-throw-literal
166
- throw 'Dynamic imports are not allowed.'
167
- }
168
- })
169
+ const script = typeof codeOrScript !== 'string' ? codeOrScript : doCompileScript(codeOrScript, filename, safeExecution)
170
+
171
+ if (safeExecution) {
172
+ run = async () => {
173
+ return safeVM.run(script)
174
+ }
175
+ } else {
176
+ run = async () => {
177
+ return script.runInContext(vmSandbox, {
178
+ displayErrors: true
179
+ })
180
+ }
169
181
  }
170
182
 
171
183
  try {
172
- const result = await vm.run(script)
184
+ const result = await run()
173
185
  return result
174
186
  } catch (e) {
175
187
  decorateErrorMessage(e, sourceFilesInfo)
@@ -180,10 +192,53 @@ module.exports = (_sandbox, options = {}) => {
180
192
  }
181
193
  }
182
194
 
195
+ function doCompileScript (code, filename, safeExecution) {
196
+ let script
197
+
198
+ if (safeExecution) {
199
+ script = new VMScript(code, filename)
200
+
201
+ // NOTE: if we need to upgrade vm2 we will need to check the source of this function
202
+ // in vm2 repo and see if we need to change this,
203
+ // we needed to override this method because we want "displayErrors" to be true in order
204
+ // to show nice error when the compile of a script fails
205
+ script._compile = function (prefix, suffix) {
206
+ return new originalVM.Script(prefix + this.getCompiledCode() + suffix, {
207
+ __proto__: null,
208
+ filename: this.filename,
209
+ displayErrors: true,
210
+ lineOffset: this.lineOffset,
211
+ columnOffset: this.columnOffset,
212
+ // THIS FN WAS TAKEN FROM vm2 source, nothing special here
213
+ importModuleDynamically: () => {
214
+ // We can't throw an error object here because since vm.Script doesn't store a context, we can't properly contextify that error object.
215
+ // eslint-disable-next-line no-throw-literal
216
+ throw 'Dynamic imports are not allowed.'
217
+ }
218
+ })
219
+ }
220
+
221
+ // do the compilation
222
+ script._compileVM()
223
+ } else {
224
+ script = new originalVM.Script(code, {
225
+ filename,
226
+ displayErrors: true,
227
+ importModuleDynamically: () => {
228
+ // We can't throw an error object here because since vm.Script doesn't store a context, we can't properly contextify that error object.
229
+ // eslint-disable-next-line no-throw-literal
230
+ throw 'Dynamic imports are not allowed.'
231
+ }
232
+ })
233
+ }
234
+
235
+ return script
236
+ }
237
+
183
238
  function doRequire (moduleName, requirePaths = [], modulesCache) {
184
239
  const searchedPaths = []
185
240
 
186
- function safeRequire (require, modulePath) {
241
+ function optimizedRequire (require, modulePath) {
187
242
  // save the current module cache, we will use this to restore the cache to the
188
243
  // original values after the require finish
189
244
  const originalModuleCache = Object.assign(Object.create(null), require.cache)
@@ -238,13 +293,13 @@ function doRequire (moduleName, requirePaths = [], modulesCache) {
238
293
  }
239
294
  }
240
295
 
241
- let result = safeRequire(require, moduleName)
296
+ let result = optimizedRequire(require, moduleName)
242
297
 
243
298
  if (!result) {
244
299
  let pathsSearched = 0
245
300
 
246
301
  while (!result && pathsSearched < requirePaths.length) {
247
- result = safeRequire(require, path.join(requirePaths[pathsSearched], moduleName))
302
+ result = optimizedRequire(require, path.join(requirePaths[pathsSearched], moduleName))
248
303
  pathsSearched++
249
304
  }
250
305
  }