|
17 | 17 | const vm = require('vm'),
|
18 | 18 | fs = require('fs'),
|
19 | 19 | path = require('path'),
|
20 |
| - mod = require('module'), |
21 | 20 | expandHomeDir = require('expand-home-dir'),
|
22 | 21 | openwhiskComposer = require('@ibm-functions/composer'),
|
23 |
| - { isValidFSM, handleError } = require('./composer') |
| 22 | + { isValidFSM } = require('./composer') |
24 | 23 |
|
25 | 24 | //
|
26 | 25 | // just in case, block any use of wsk from within sandboxed compilations
|
@@ -87,184 +86,95 @@ exports.compileToFSM = (src, opts={}) => new Promise((resolve, reject) => {
|
87 | 86 | return reject({ message: 'No code to compile', type: 'EMPTY_FILE'})
|
88 | 87 | }
|
89 | 88 |
|
90 |
| - /** |
91 |
| - * The Composer constructor tries to initialize |
92 |
| - * wsk. But we may not have a wskprops, e.g. if the |
93 |
| - * user is previewing apps without any AUTH |
94 |
| - * configuration. See |
95 |
| - * tests/passes/07/composer-viz-no-auth.js |
96 |
| - * |
97 |
| - */ |
98 |
| - |
99 |
| - // check to see if the source already requires the openwhisk-composer library |
100 |
| - function bootstrapWithRequire() { |
101 |
| - lineOffset = 1 |
102 |
| - return `const composer = require('@ibm-functions/composer');` + originalCode |
103 |
| - } |
104 |
| - function bootstrapWithRequireForModule() { |
105 |
| - lineOffset = 1 |
106 |
| - return `const composer = require('@ibm-functions/composer')const process = module.process; const console = module.console;\n` + originalCode |
107 |
| - } |
108 |
| - function bootstrapWithModuleExports() { |
109 |
| - lineOffset = 0 |
110 |
| - return "const process = module.process; const console = module.console; module.exports=" + originalCode |
111 |
| - } |
112 |
| - function bootstrapWithModuleExportsAndRequire() { |
113 |
| - lineOffset = 0 |
114 |
| - return `const composer = require('@ibm-functions/composer'); const process = module.process; const console = module.console; module.exports=` + originalCode |
115 |
| - } |
116 |
| - function bootstrapWithModuleExportsAndRequireAndTrim() { |
117 |
| - lineOffset = 0 |
118 |
| - const code = originalCode.trim().replace(/^([;\s]+)/, '') // trim leading semicolons |
119 |
| - return `const composer = require('@ibm-functions/composer'); const process = module.process; const console = module.console; module.exports=` + code |
120 |
| - } |
121 |
| - function bootstrapWithConstMain() { |
122 |
| - lineOffset = 1 |
123 |
| - return "const process = module.process; const console = module.console;" + originalCode + "\n;module.exports=main" |
124 |
| - } |
125 |
| - function bootstrapWithConstMainAndRequire() { |
126 |
| - lineOffset = 1 |
127 |
| - return `const composer = require('@ibm-functions/composer'); const process = module.process; const console = module.console;\n` + originalCode + "\n;module.exports=main" |
128 |
| - } |
129 |
| - |
130 |
| - const retryA = [bootstrapWithRequireForModule, |
131 |
| - bootstrapWithModuleExports, |
132 |
| - bootstrapWithModuleExportsAndRequire, |
133 |
| - bootstrapWithModuleExportsAndRequireAndTrim, |
134 |
| - bootstrapWithConstMain, |
135 |
| - bootstrapWithConstMainAndRequire] |
136 |
| - |
137 | 89 | let errorMessage = '',
|
138 | 90 | logMessage = '' // TODO this isn't flowing through, yet
|
139 |
| - const doLog = msg => logMessage += msg + '\n', |
140 |
| - doExit = () => reject({ |
141 |
| - fsm: errorMessage, |
142 |
| - code: originalCode |
143 |
| - }) |
144 | 91 | const errors = []
|
145 |
| - const compile = (code, retries=retryA) => { |
| 92 | + const compile = code => { |
146 | 93 | errorMessage = ''
|
147 | 94 | logMessage = ''
|
148 | 95 | try {
|
149 |
| - const module = { exports: {}, |
150 |
| - process: { env: opts.env || process.env, exit: doExit }, |
151 |
| - console: { error: msg => errorMessage += msg + '\n', |
152 |
| - log: doLog } |
153 |
| - }, |
154 |
| - my_require = m => { |
155 |
| - if (m === '@ibm-functions/composer') { |
156 |
| - return openwhiskComposer |
157 |
| - } else { |
158 |
| - return require(path.resolve(dir, m)) |
| 96 | + const doExit = () => reject({ |
| 97 | + fsm: errorMessage, |
| 98 | + code: originalCode |
| 99 | + }) |
| 100 | + |
| 101 | + const my = { |
| 102 | + process: Object.assign(process, { |
| 103 | + env: Object.assign({}, process.env, opts.env), // merge -e from the command line |
| 104 | + exit: doExit // override process.exit() |
| 105 | + }), |
| 106 | + console: { |
| 107 | + error: msg => errorMessage += msg + '\n', |
| 108 | + log: msg => logMessage += msg + '\n' |
| 109 | + }, |
| 110 | + require: m => { |
| 111 | + if (m === '@ibm-functions/composer') { |
| 112 | + return openwhiskComposer |
| 113 | + } else { |
| 114 | + return require(path.resolve(dir, m)) |
| 115 | + |
| 116 | + } |
| 117 | + } |
| 118 | + } |
| 119 | + |
| 120 | + const module = { |
| 121 | + exports: {} |
| 122 | + } |
| 123 | + const sandbox = { |
| 124 | + module, |
| 125 | + exports: module.exports, |
| 126 | + filename, |
| 127 | + lineOffset, |
| 128 | + console: my.console, |
| 129 | + process: my.process, |
| 130 | + require: my.require |
| 131 | + } |
| 132 | + const sandboxWithComposer = Object.assign(sandbox, { composer: openwhiskComposer }) |
159 | 133 |
|
160 |
| - } |
161 |
| - } |
| 134 | + let res = vm.runInNewContext(code, sandboxWithComposer) |
| 135 | + debug('res', typeof res, res) |
162 | 136 |
|
163 |
| - const sandbox = {} |
164 |
| - module.exports = {} |
165 |
| - let res = vm.runInNewContext(mod.wrap(code), { filename, lineOffset, console: module.console, process: module.process })(module.exports, my_require, module, filename, dir) || module.exports.main || module.exports || res.main |
166 |
| - //console.error(code) |
167 | 137 | if (typeof res === 'function') {
|
168 | 138 | res = res()
|
169 | 139 | }
|
170 | 140 |
|
171 | 141 | if (isValidFSM(res)) {
|
172 | 142 | return res
|
| 143 | + |
173 | 144 | } else {
|
| 145 | + let err = '' |
174 | 146 | try {
|
175 | 147 | // maybe the code did a console.log?
|
176 | 148 | const maybe = openwhiskComposer.deserialize(JSON.parse(logMessage))
|
177 | 149 | if (isValidFSM(maybe)) {
|
178 | 150 | return maybe
|
179 | 151 | }
|
180 |
| - } catch (e) { } |
181 |
| - |
182 |
| - throw new Error('Unable to compile your composition') |
183 |
| - } |
184 |
| - } catch (e) { |
185 |
| - console.error(e) |
186 |
| - errors.push(e) |
187 |
| - if (retries.length > 0) { |
188 |
| - return compile(retries.pop()(), retries) |
189 |
| - } |
190 |
| - |
191 |
| - const log = console.log, exit = process.exit |
192 |
| - console.log = doLog |
193 |
| - process.exit = doExit |
194 |
| - try { |
195 |
| - errorMessage = '' |
196 |
| - const tmp = save(process.env, opts.env) |
197 |
| - try { |
198 |
| - const json = eval(originalCode) |
199 |
| - if (isValidFSM(json)) { |
200 |
| - return json |
201 |
| - } else { |
202 |
| - const maybe = json |
203 |
| - console.log = log |
204 |
| - process.exit = exit |
205 |
| - return maybe |
206 |
| - } |
207 |
| - } finally { |
208 |
| - restore(process.env, tmp) |
| 152 | + } catch (e) { |
| 153 | + err = e |
209 | 154 | }
|
210 |
| - } catch (e2) { |
211 |
| - console.log = log |
212 |
| - process.exit = exit |
213 |
| - try { |
214 |
| - // maybe the user logged a compiled fsm? |
215 |
| - const maybe = JSON.parse(logMessage) |
216 |
| - if (isValidFSM(maybe)) { |
217 |
| - return maybe |
218 |
| - } |
219 |
| - } catch (e3) { |
220 |
| - try { |
221 |
| - console.log = doLog |
222 |
| - process.exit = doExit |
223 |
| - errorMessage = '' |
224 |
| - const tmp = save(process.env, opts.env) |
225 |
| - try { |
226 |
| - const composition = eval(bootstrapWithRequire(originalCode)) |
227 |
| - console.log = log |
228 |
| - process.exit = exit |
229 |
| - return composition |
230 |
| - } finally { |
231 |
| - restore(process.env, tmp) |
232 |
| - } |
233 |
| - |
234 |
| - } catch (e4) { |
235 |
| - console.log = log |
236 |
| - process.exit = exit |
237 |
| - // some sort of parse or runtime error with the composer source file |
238 |
| - // note that we take care to elide our junk on any error stacks (junkMatch) |
239 |
| - //console.error(mod.wrap(code)) |
240 |
| - //console.error(errorMessage) |
241 | 155 |
|
242 |
| - const goodMsg = e => e.message.indexOf('has already been declared') < 0 |
243 |
| - && e.message.indexOf('composer is not defined') < 0 |
244 |
| - && e |
245 |
| - const err = errors.find(goodMsg) || goodMsg(e2) || goodMsg(e3) || e4 |
246 |
| - |
247 |
| - const junkMatch = err.stack.match(/\s+at Object\.exports\.runInNewContext/) |
248 |
| - || err.stack.match(/\s+at Object\.runInNewContext/) |
249 |
| - || err.stack.match(/\s+at fs\.readFile/), |
250 |
| - _message = err.message.indexOf('Invalid argument to compile') >= 0? 'Your source code did not produce a valid app.' : (!junkMatch ? e.stack : err.stack.substring(0, junkMatch.index).replace(/\s+.*create-from-source([^\n])*/g, '\n').replace(/(evalmachine.<anonymous>)/g, filename).replace(/\s+at createScript([^\n])*/g, '\n').trim()), |
251 |
| - message = _message.replace(/\s+\(.*plugins\/modules\/composer\/node_modules\/@ibm-functions\/composer\/composer\.js:[^\s]*/, '') |
| 156 | + throw new Error(`Unable to compile your composition |
| 157 | +${err} |
| 158 | +${errorMessage}`) |
| 159 | + } |
| 160 | + } catch (err) { |
| 161 | + const junkMatch = err.stack.match(/\s+at Object\.exports\.runInNewContext/) |
| 162 | + || err.stack.match(/\s+at Object\.runInNewContext/) |
| 163 | + || err.stack.match(/\s+at fs\.readFile/), |
| 164 | + _message = err.message.indexOf('Invalid argument to compile') >= 0? 'Your source code did not produce a valid app.' : (!junkMatch ? e.stack : err.stack.substring(0, junkMatch.index).replace(/\s+.*create-from-source([^\n])*/g, '\n').replace(/(evalmachine.<anonymous>)/g, filename).replace(/\s+at createScript([^\n])*/g, '\n').trim()), |
| 165 | + message = _message |
| 166 | + .replace(/\s+\(.*plugins\/modules\/composer\/node_modules\/@ibm-functions\/composer\/composer\.js:[^\s]*/, '') |
| 167 | + .replace(/\s+at ContextifyScript[^\n]*/g, '') |
252 | 168 |
|
253 |
| - console.error('All composer create/preview errors are here', errors) |
254 |
| - console.error('Selected error', err) |
255 |
| - console.error('Selected message', message, junkMatch) |
256 | 169 |
|
257 |
| - // for parse error, error message is shown in the fsm (JSON) tab, and user code in the source (code) tab |
258 |
| - // reject now returns {fsm:errMsg, code:originalCode} |
259 |
| - reject( |
260 |
| - { |
261 |
| - fsm: message, |
262 |
| - code: originalCode |
263 |
| - } |
264 |
| - ) |
265 |
| - } |
| 170 | + // for parse error, error message is shown in the fsm (JSON) tab, and user code in the source (code) tab |
| 171 | + // reject now returns {fsm:errMsg, code:originalCode} |
| 172 | + reject( |
| 173 | + { |
| 174 | + fsm: message, |
| 175 | + code: originalCode |
266 | 176 | }
|
267 |
| - } |
| 177 | + ) |
268 | 178 | }
|
269 | 179 | }
|
270 | 180 | let fsm
|
|
0 commit comments