(code, sandbox)
| 266 | } |
| 267 | |
| 268 | function preprocess(code, sandbox) { |
| 269 | if (typeof code != "string") { |
| 270 | if (code.apply) { |
| 271 | let orig = code |
| 272 | code = (...args) => { |
| 273 | try { return orig.apply(null, args) } |
| 274 | catch(e) { sandbox.error(e) } |
| 275 | } |
| 276 | } |
| 277 | return {code, dependencies: []} |
| 278 | } |
| 279 | |
| 280 | if (!/\n$/.test(code)) code += "\n" |
| 281 | let strict = /^(\s|\/\/.*)*["']use strict['"]/.test(code), ast |
| 282 | try { ast = parse(code, {sourceType: detectSourceType(code), ecmaVersion: "latest"}) } |
| 283 | catch(e) { return {code, dependencies: []} } |
| 284 | let patches = [] |
| 285 | let backJump = ";if (++__c % 1000 === 0) __sandbox.tick();" |
| 286 | function loop(node) { |
| 287 | if (node.body.type == "BlockStatement") { |
| 288 | patches.push({from: node.body.end - 1, text: backJump}) |
| 289 | } else { |
| 290 | patches.push({from: node.body.start, text: "{"}, |
| 291 | {from: node.body.end, text: backJump + "}"}) |
| 292 | } |
| 293 | } |
| 294 | let dependencies = [] |
| 295 | |
| 296 | walk.simple(ast, { |
| 297 | ForStatement: loop, |
| 298 | ForInStatement: loop, |
| 299 | WhileStatement: loop, |
| 300 | DoWhileStatement: loop, |
| 301 | CallExpression(node) { |
| 302 | if (node.callee.type == "Identifier" && node.callee.name == "require" && |
| 303 | node.arguments.length == 1 && node.arguments[0].type == "Literal" && |
| 304 | typeof node.arguments[0].value == "string" && !dependencies.includes(node.arguments[0].value)) |
| 305 | dependencies.push(node.arguments[0].value) |
| 306 | }, |
| 307 | ImportDeclaration(node) { |
| 308 | dependencies.push(node.source.value) |
| 309 | let req = "require(" + node.source.raw + ")", text |
| 310 | if (node.specifiers.length == 0) { |
| 311 | text = req |
| 312 | } else if (node.specifiers.length > 1 || node.specifiers[0].type == "ImportDefaultSpecifier") { |
| 313 | let name = "m_" + node.source.value.replace(/\W+/g, "_") + "__" |
| 314 | text = "var " + name + " = " + req |
| 315 | node.specifiers.forEach(spec => { |
| 316 | if (spec.type == "ImportDefaultSpecifier") |
| 317 | text += ", " + spec.local.name + " = " + name + ".default || " + name |
| 318 | else if (name != null) |
| 319 | text += ", " + spec.local.name + " = " + name + "." + spec.imported.name |
| 320 | }) |
| 321 | } else { |
| 322 | text = "var " |
| 323 | node.specifiers.forEach(spec => { |
| 324 | if (spec.type == "ImportNamespaceSpecifier") |
| 325 | text += spec.local.name + " = " + req |
no test coverage detected