UNPKG

sandbox-editor

Version:

Edit JS file in the browser and execute them inside a sandbox environment

77 lines (74 loc) 2.69 kB
const Fs = require("fs"); const Path = require("path"); const Browserify = require("browserify"); const Resolve = require("resolve"); const Stream = require("stream"); module.exports = (path, options, callback) => { options = options || {}; options.basedir = String(options.basedir || process.cwd()); options.editor = options.editor || {}; options.noprocess = Boolean(options.noprocess); options.nobuffer = Boolean(options.nobuffer); const sandbox = { type: "browserify", path: "/"+Path.relative(options.basedir, path), editor: options.editor, modules: [], }; Fs.readFile(path, "utf8", (error, content) => { if (error) return callback(error); const browserify = Browserify({detectGlobals:false}); const add = (module, expose) => { browserify.require(module, {expose:expose}); sandbox.modules.push(expose); }; ((() => { const shim = (variable, expose) => { const readable = new Stream.Readable({read:()=>{}}); readable.push("module.exports = "+variable+";"); readable.push(null); if (!options["no"+expose]) add(expose, "_"+expose); add(readable, expose); }; shim("process", "process"); shim("Buffer", "buffer"); }) ()); browserify.transform((file) => { let content = ""; const stream = new Stream.Transform({ decodeStrings: false, transform: (chunk, encoding, callback) => { content += chunk; stream.push(chunk, encoding); callback(); }, flush: (callback) => { const filename = "/"+Path.relative(options.basedir, file); stream.push("\n}) ("+JSON.stringify(filename)+","+JSON.stringify(Path.dirname(filename))+"));"); callback(); } }); stream.push("(((__filename, __dirname) => {\n"); return stream; }, {global:true}); sandbox.content = content.replace(/([^a-zA-Z0-9_$]|^)require\s*\(\s*(("[^"]*")|('[^']*'))\s*\)/g, (match, p1, p2) => { let module = eval(p2); if (module[0] === ".") module = Path.resolve(Path.dirname(path), module); const expose = module[0] === "/" ? "/"+Path.relative(options.basedir, module) : module; if (module[0] !== "/" && !Resolve.isCore(module)) module = Resolve.sync(module, {basedir:Path.dirname(path)}); if (sandbox.modules.indexOf(module) === -1) add(module, expose); return p1+"require("+JSON.stringify(expose)+")"; }); browserify.bundle((error, bundle) => { if (error) return callback(error); sandbox.require = bundle.toString("utf8"); callback(null, sandbox); }); }); };