@jsreport/jsreport-core 3.4.1 → 3.6.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.
@@ -9,11 +9,13 @@ 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()
18
+ const executionAsyncResultsMap = new Map()
17
19
 
18
20
  const templatingEnginesEvaluate = async (mainCall, { engine, content, helpers, data }, { entity, entitySet }, req) => {
19
21
  const engineImpl = reporter.extensionsManager.engines.find((e) => e.name === engine)
@@ -28,19 +30,23 @@ module.exports = (reporter) => {
28
30
  executionFnParsedParamsMap.set(req.context.id, new Map())
29
31
  }
30
32
 
33
+ const executionId = nanoid(7)
34
+
31
35
  try {
32
36
  const res = await executeEngine({
33
37
  engine: engineImpl,
34
38
  content,
35
39
  helpers,
36
40
  data
37
- }, { handleErrors: false, entity, entitySet }, req)
41
+ }, { executionId, handleErrors: false, entity, entitySet }, req)
38
42
 
39
43
  return res.content
40
44
  } finally {
41
45
  if (mainCall) {
42
46
  executionFnParsedParamsMap.delete(req.context.id)
43
47
  }
48
+
49
+ executionAsyncResultsMap.delete(executionId)
44
50
  }
45
51
  }
46
52
 
@@ -54,6 +60,39 @@ module.exports = (reporter) => {
54
60
  proxy.templatingEngines = {
55
61
  evaluate: async (executionInfo, entityInfo) => {
56
62
  return templatingEnginesEvaluate(false, executionInfo, entityInfo, req)
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
+ },
91
+ waitForAsyncHelpers: async () => {
92
+ if (context.__executionId != null && executionAsyncResultsMap.has(context.__executionId)) {
93
+ const asyncResultMap = executionAsyncResultsMap.get(context.__executionId)
94
+ return Promise.all([...asyncResultMap.keys()].map((k) => asyncResultMap.get(k)))
95
+ }
57
96
  }
58
97
  }
59
98
  })
@@ -64,6 +103,8 @@ module.exports = (reporter) => {
64
103
  req.data.__rootDirectory = reporter.options.rootDirectory
65
104
  req.data.__parentModuleDirectory = reporter.options.parentModuleDirectory
66
105
 
106
+ const executionId = nanoid(7)
107
+
67
108
  try {
68
109
  return await executeEngine({
69
110
  engine,
@@ -71,55 +112,88 @@ module.exports = (reporter) => {
71
112
  helpers: req.template.helpers,
72
113
  data: req.data
73
114
  }, {
115
+ executionId,
74
116
  handleErrors: true,
75
117
  entity: req.template,
76
118
  entitySet: 'templates'
77
119
  }, req)
78
120
  } finally {
79
121
  executionFnParsedParamsMap.delete(req.context.id)
122
+ executionAsyncResultsMap.delete(executionId)
80
123
  }
81
124
  }
82
125
 
83
- async function executeEngine ({ engine, content, helpers, data }, { handleErrors, entity, entitySet }, req) {
126
+ async function executeEngine ({ engine, content, helpers, data }, { executionId, handleErrors, entity, entitySet }, req) {
84
127
  let entityPath
85
128
 
86
129
  if (entity._id) {
87
130
  entityPath = await reporter.folders.resolveEntityPath(entity, entitySet, req)
88
131
  }
89
132
 
90
- const registerResults = await reporter.registerHelpersListeners.fire(req)
91
- const systemHelpers = []
133
+ const normalizedHelpers = `${helpers || ''}`
134
+ const executionFnParsedParamsKey = `entity:${entity.shortid || 'anonymous'}:helpers:${normalizedHelpers}`
92
135
 
93
- for (const result of registerResults) {
94
- if (result == null) {
95
- continue
136
+ const initFn = async (getTopLevelFunctions, compileScript) => {
137
+ if (systemHelpersCache != null) {
138
+ return systemHelpersCache
96
139
  }
97
140
 
98
- if (typeof result === 'string') {
99
- systemHelpers.push(result)
141
+ const registerResults = await reporter.registerHelpersListeners.fire()
142
+ const systemHelpers = []
143
+
144
+ for (const result of registerResults) {
145
+ if (result == null) {
146
+ continue
147
+ }
148
+
149
+ if (typeof result === 'string') {
150
+ systemHelpers.push(result)
151
+ }
100
152
  }
101
- }
102
153
 
103
- const systemHelpersStr = systemHelpers.join('\n')
104
- const joinedHelpers = systemHelpersStr + '\n' + (helpers || '')
105
- const executionFnParsedParamsKey = `entity:${entity.shortid || 'anonymous'}:helpers:${joinedHelpers}`
154
+ const systemHelpersStr = systemHelpers.join('\n')
155
+
156
+ const functionNames = getTopLevelFunctions(systemHelpersStr)
106
157
 
107
- const executionFn = async ({ require, console, topLevelFunctions }) => {
158
+ const exposeSystemHelpersCode = `for (const fName of ${JSON.stringify(functionNames)}) { this[fName] = __topLevelFunctions[fName] }`
159
+
160
+ // we sync the __topLevelFunctions with system helpers and expose it immediately to the global context
161
+ const userCode = `(async () => { ${systemHelpersStr};
162
+ __topLevelFunctions = {...__topLevelFunctions, ${functionNames.map(h => `"${h}": ${h}`).join(',')}}; ${exposeSystemHelpersCode}
163
+ })()`
164
+
165
+ const filename = 'system-helpers.js'
166
+ const script = compileScript(userCode, filename)
167
+
168
+ systemHelpersCache = {
169
+ filename,
170
+ source: systemHelpersStr,
171
+ script
172
+ }
173
+
174
+ return systemHelpersCache
175
+ }
176
+
177
+ const executionFn = async ({ require, console, topLevelFunctions, context }) => {
108
178
  const asyncResultMap = new Map()
109
- executionFnParsedParamsMap.get(req.context.id).get(executionFnParsedParamsKey).resolve({ require, console, topLevelFunctions })
179
+
180
+ context.__executionId = executionId
181
+
182
+ executionAsyncResultsMap.set(executionId, asyncResultMap)
183
+ executionFnParsedParamsMap.get(req.context.id).get(executionFnParsedParamsKey).resolve({ require, console, topLevelFunctions, context })
184
+
110
185
  const key = `template:${content}:${engine.name}`
111
186
 
112
- if (!cache.has(key)) {
187
+ if (!templatesCache.has(key)) {
113
188
  try {
114
- cache.set(key, engine.compile(content, { require }))
189
+ templatesCache.set(key, engine.compile(content, { require }))
115
190
  } catch (e) {
116
191
  e.property = 'content'
117
192
  throw e
118
193
  }
119
194
  }
120
195
 
121
- const compiledTemplate = cache.get(key)
122
-
196
+ const compiledTemplate = templatesCache.get(key)
123
197
  const wrappedTopLevelFunctions = {}
124
198
 
125
199
  for (const h of Object.keys(topLevelFunctions)) {
@@ -127,7 +201,9 @@ module.exports = (reporter) => {
127
201
  }
128
202
 
129
203
  let contentResult = await engine.execute(compiledTemplate, wrappedTopLevelFunctions, data, { require })
204
+
130
205
  const resolvedResultsMap = new Map()
206
+
131
207
  while (asyncResultMap.size > 0) {
132
208
  await Promise.all([...asyncResultMap.keys()].map(async (k) => {
133
209
  resolvedResultsMap.set(k, `${await asyncResultMap.get(k)}`)
@@ -143,26 +219,31 @@ module.exports = (reporter) => {
143
219
  }
144
220
 
145
221
  return {
146
- content: contentResult
222
+ // handlebars escapes single brackets before execution to prevent errors on {#asset}
223
+ // we need to unescape them later here, because at the moment the engine.execute finishes
224
+ // the async helpers aren't executed yet
225
+ content: engine.unescape ? engine.unescape(contentResult) : contentResult
147
226
  }
148
227
  }
149
228
 
150
229
  // executionFnParsedParamsMap is there to cache parsed components helpers to speed up longer loops
151
230
  // we store there for the particular request and component a promise and only the first component gets compiled
152
231
  if (executionFnParsedParamsMap.get(req.context.id).has(executionFnParsedParamsKey)) {
153
- const { require, console, topLevelFunctions } = await (executionFnParsedParamsMap.get(req.context.id).get(executionFnParsedParamsKey).promise)
232
+ const { require, console, topLevelFunctions, context } = await (executionFnParsedParamsMap.get(req.context.id).get(executionFnParsedParamsKey).promise)
154
233
 
155
- return executionFn({ require, console, topLevelFunctions })
234
+ return executionFn({ require, console, topLevelFunctions, context })
156
235
  } else {
157
236
  const awaiter = {}
237
+
158
238
  awaiter.promise = new Promise((resolve) => {
159
239
  awaiter.resolve = resolve
160
240
  })
241
+
161
242
  executionFnParsedParamsMap.get(req.context.id).set(executionFnParsedParamsKey, awaiter)
162
243
  }
163
244
 
164
245
  if (reporter.options.sandbox.cache && reporter.options.sandbox.cache.enabled === false) {
165
- cache.reset()
246
+ templatesCache.reset()
166
247
  }
167
248
 
168
249
  try {
@@ -170,10 +251,10 @@ module.exports = (reporter) => {
170
251
  context: {
171
252
  ...(engine.createContext ? engine.createContext() : {})
172
253
  },
173
- userCode: joinedHelpers,
254
+ userCode: normalizedHelpers,
255
+ initFn,
174
256
  executionFn,
175
257
  currentPath: entityPath,
176
- errorLineNumberOffset: systemHelpersStr.split('\n').length,
177
258
  onRequire: (moduleName, { context }) => {
178
259
  if (engine.onRequire) {
179
260
  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
 
@@ -57,9 +57,9 @@ class Profiler {
57
57
 
58
58
  if (m.type !== 'log') {
59
59
  req.context.profiling.lastEventId = m.id
60
+ m.operationId = m.operationId || generateRequestId()
60
61
  }
61
62
 
62
- m.operationId = m.operationId || generateRequestId()
63
63
  if (m.previousOperationId == null && req.context.profiling.lastOperationId) {
64
64
  m.previousOperationId = req.context.profiling.lastOperationId
65
65
  }
@@ -72,15 +72,21 @@ class Profiler {
72
72
  let content = res.content
73
73
 
74
74
  if (content != null) {
75
- if (isbinaryfile(content)) {
75
+ if (content.length > this.reporter.options.profiler.maxDiffSize) {
76
76
  content = {
77
- content: res.content.toString('base64'),
78
- encoding: 'base64'
77
+ tooLarge: true
79
78
  }
80
79
  } else {
81
- content = {
82
- content: createPatch('res', req.context.profiling.resLastVal ? req.context.profiling.resLastVal.toString() : '', res.content.toString(), 0),
83
- encoding: 'diff'
80
+ if (isbinaryfile(content)) {
81
+ content = {
82
+ content: res.content.toString('base64'),
83
+ encoding: 'base64'
84
+ }
85
+ } else {
86
+ content = {
87
+ content: createPatch('res', req.context.profiling.resLastVal ? req.context.profiling.resLastVal.toString() : '', res.content.toString(), 0),
88
+ encoding: 'diff'
89
+ }
84
90
  }
85
91
  }
86
92
  }
@@ -91,9 +97,14 @@ class Profiler {
91
97
 
92
98
  const stringifiedReq = JSON.stringify({ template: req.template, data: req.data }, null, 2)
93
99
 
94
- m.req = { diff: createPatch('req', req.context.profiling.reqLastVal || '', stringifiedReq, 0) }
100
+ m.req = { }
101
+ if (stringifiedReq.length * 4 > this.reporter.options.profiler.maxDiffSize) {
102
+ m.req.tooLarge = true
103
+ } else {
104
+ m.req.diff = createPatch('req', req.context.profiling.reqLastVal || '', stringifiedReq, 0)
105
+ }
95
106
 
96
- req.context.profiling.resLastVal = (res.content == null || isbinaryfile(res.content)) ? null : res.content.toString()
107
+ req.context.profiling.resLastVal = (res.content == null || isbinaryfile(res.content) || content.tooLarge) ? null : res.content.toString()
97
108
  req.context.profiling.resMetaLastVal = stringifiedResMeta
98
109
  req.context.profiling.reqLastVal = stringifiedReq
99
110
  }
@@ -129,10 +140,6 @@ class Profiler {
129
140
  previousOperationId: parentReq ? parentReq.context.profiling.lastOperationId : null
130
141
  }
131
142
 
132
- if (!req.context.isChildRequest) {
133
- profilerEvent.profileId = req.context.profiling.entity._id
134
- }
135
-
136
143
  return this.emit(profilerEvent, req, res)
137
144
  }
138
145
 
@@ -10,7 +10,6 @@ const Request = require('../../shared/request')
10
10
  const generateRequestId = require('../../shared/generateRequestId')
11
11
  const resolveReferences = require('./resolveReferences.js')
12
12
  const moduleHelper = require('./moduleHelper')
13
- let reportCounter = 0
14
13
 
15
14
  module.exports = (reporter) => {
16
15
  moduleHelper(reporter)
@@ -127,9 +126,6 @@ module.exports = (reporter) => {
127
126
  response.meta.reportName = 'report'
128
127
  }
129
128
 
130
- request.context.reportCounter = ++reportCounter
131
- request.context.startTimestamp = new Date().getTime()
132
-
133
129
  if (parentReq == null) {
134
130
  reporter.requestModulesCache.set(request.context.rootId, Object.create(null))
135
131
  }
@@ -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,28 +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
- // NOTE: we wrap the Contextify.object, Decontextify.object methods because those are the
117
- // methods that returns the proxies created by vm2 in the sandbox, we want to have a list of those
118
- // to later use them
119
- const wrapAndSaveProxyResult = (originalFn, thisArg) => {
120
- return (value, ...args) => {
121
- const result = originalFn.call(thisArg, value, ...args)
118
+ if (safeExecution) {
119
+ safeVM = new VM()
122
120
 
123
- if (result != null && result.isVMProxy === true) {
124
- proxiesInVM.set(result, value)
125
- }
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
126
124
 
127
- return result
125
+ for (const name in sandbox) {
126
+ safeVM.setGlobal(name, sandbox[name])
128
127
  }
129
- }
130
128
 
131
- vm._internal.Contextify.object = wrapAndSaveProxyResult(vm._internal.Contextify.object, vm._internal.Contextify)
132
- vm._internal.Decontextify.object = wrapAndSaveProxyResult(vm._internal.Decontextify.object, vm._internal.Decontextify)
129
+ vmSandbox = safeVM.sandbox
130
+ } else {
131
+ vmSandbox = originalVM.createContext(undefined)
132
+ vmSandbox.Buffer = Buffer
133
133
 
134
- for (const name in sandbox) {
135
- vm._internal.Contextify.setGlobal(name, sandbox[name])
134
+ for (const name in sandbox) {
135
+ vmSandbox[name] = sandbox[name]
136
+ }
136
137
  }
137
138
 
138
139
  // processing top level props because getter/setter descriptors
@@ -141,57 +142,46 @@ module.exports = (_sandbox, options = {}) => {
141
142
  const currentConfig = propsConfig[key]
142
143
 
143
144
  if (currentConfig.root && currentConfig.root.sandboxReadOnly) {
144
- readOnlyProp(vm._context, key, [], customProxies, { onlyTopLevel: true })
145
+ readOnlyProp(vmSandbox, key, [], customProxies, { onlyTopLevel: true })
145
146
  }
146
147
  })
147
148
 
148
149
  const sourceFilesInfo = new Map()
149
150
 
150
151
  return {
151
- sandbox: vm._context,
152
+ sandbox: vmSandbox,
152
153
  console: _console,
153
154
  sourceFilesInfo,
154
- contextifyValue: (value) => {
155
- return vm._internal.Contextify.value(value)
156
- },
157
- decontextifyValue: (value) => {
158
- return vm._internal.Decontextify.value(value)
155
+ compileScript: (code, filename) => {
156
+ return doCompileScript(code, filename, safeExecution)
159
157
  },
160
158
  restore: () => {
161
- return restoreProperties(vm._context, originalValues, proxiesInVM, customProxies)
162
- },
163
- unproxyValue: (value) => {
164
- return getOriginalFromProxy(proxiesInVM, customProxies, value)
159
+ return restoreProperties(vmSandbox, originalValues, proxiesInVM, customProxies)
165
160
  },
166
- safeRequire: (modulePath) => _require(modulePath, { context: _sandbox, allowAllModules: true }),
167
- run: async (code, { filename, errorLineNumberOffset = 0, source, entity, entitySet } = {}) => {
168
- 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
169
164
 
170
165
  if (filename != null && source != null) {
171
166
  sourceFilesInfo.set(filename, { filename, source, entity, entitySet, errorLineNumberOffset })
172
167
  }
173
168
 
174
- // NOTE: if we need to upgrade vm2 we will need to check the source of this function
175
- // in vm2 repo and see if we need to change this,
176
- // we needed to override this method because we want "displayErrors" to be true in order
177
- // to show nice error when the compile of a script fails
178
- script._compile = function (prefix, suffix) {
179
- return new originalVM.Script(prefix + this.getCompiledCode() + suffix, {
180
- filename: this.filename,
181
- displayErrors: true,
182
- lineOffset: this.lineOffset,
183
- columnOffset: this.columnOffset,
184
- // THIS FN WAS TAKEN FROM vm2 source, nothing special here
185
- importModuleDynamically: () => {
186
- // 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.
187
- // eslint-disable-next-line no-throw-literal
188
- throw 'Dynamic imports are not allowed.'
189
- }
190
- })
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
+ }
191
181
  }
192
182
 
193
183
  try {
194
- const result = await vm.run(script)
184
+ const result = await run()
195
185
  return result
196
186
  } catch (e) {
197
187
  decorateErrorMessage(e, sourceFilesInfo)
@@ -202,10 +192,53 @@ module.exports = (_sandbox, options = {}) => {
202
192
  }
203
193
  }
204
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
+
205
238
  function doRequire (moduleName, requirePaths = [], modulesCache) {
206
239
  const searchedPaths = []
207
240
 
208
- function safeRequire (require, modulePath) {
241
+ function optimizedRequire (require, modulePath) {
209
242
  // save the current module cache, we will use this to restore the cache to the
210
243
  // original values after the require finish
211
244
  const originalModuleCache = Object.assign(Object.create(null), require.cache)
@@ -260,13 +293,13 @@ function doRequire (moduleName, requirePaths = [], modulesCache) {
260
293
  }
261
294
  }
262
295
 
263
- let result = safeRequire(require, moduleName)
296
+ let result = optimizedRequire(require, moduleName)
264
297
 
265
298
  if (!result) {
266
299
  let pathsSearched = 0
267
300
 
268
301
  while (!result && pathsSearched < requirePaths.length) {
269
- result = safeRequire(require, path.join(requirePaths[pathsSearched], moduleName))
302
+ result = optimizedRequire(require, path.join(requirePaths[pathsSearched], moduleName))
270
303
  pathsSearched++
271
304
  }
272
305
  }