Skip to content

Commit

Permalink
Merge pull request #245 from XmiliaH/per-script-compiler
Browse files Browse the repository at this point in the history
Allow to specify a compiler per VMScript.
  • Loading branch information
patriksimek committed Sep 14, 2019
2 parents 284a518 + d674d43 commit 78f8be5
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 29 deletions.
66 changes: 37 additions & 29 deletions lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,42 @@ const pa = require('path');
const {EventEmitter} = require('events');
const {INSPECT_MAX_BYTES} = require('buffer');

const _compileToJS = function compileToJS(code, compiler, filename) {
if ('function' === typeof compiler) return compiler(code, filename);
const COFFEE_SCRIPT_COMPILER = {compiler: null};
function getCoffeeScriptCompiler() {
if (!COFFEE_SCRIPT_COMPILER.compiler) {
try {
const coffeeScript = require('coffee-script');
COFFEE_SCRIPT_COMPILER.compiler = (code, filename) => {
return coffeeScript.compile(code, {header: false, bare: true});
};
} catch (e) {
throw new VMError('Coffee-Script compiler is not installed.');
}
}
return COFFEE_SCRIPT_COMPILER.compiler;
}

function jsCompiler(code, filename) {
return code;
}

function lookupCompiler(compiler) {
if ('function' === typeof compiler) return compiler;
switch (compiler) {
case 'coffeescript':
case 'coffee-script':
case 'cs':
case 'text/coffeescript':
try {
return require('coffee-script').compile(code, {header: false, bare: true});
} catch (ex) {
throw new VMError('Coffee-Script compiler is not installed.');
}

return getCoffeeScriptCompiler();
case 'javascript':
case 'java-script':
case 'js':
case 'text/javascript':
return code;

return jsCompiler;
default:
throw new VMError(`Unsupported compiler '${compiler}'.`);
}
};
}

/**
* Class Script
Expand All @@ -51,12 +63,14 @@ class VMScript {

constructor(code, filename, options) {
this._code = String(code);
this.filename = filename || 'vm.js';
this.options = options || {};
this.filename = filename || this.options.filename || 'vm.js';
this._prefix = '';
this._suffix = '';
this._compiledVM = null;
this._compiledNodeVM = null;
this._compiler = lookupCompiler(this.options.compiler || 'javascript');
this._unresolvedFilename = this.options.filename || this.filename;
}

/**
Expand Down Expand Up @@ -120,7 +134,7 @@ class VMScript {
_compileVM() {
if (this._compiledVM) return this;

this._compiledVM = new vm.Script(this._prefix + this._code + this._suffix, {
this._compiledVM = new vm.Script(this._compiler(this._prefix + this._code + this._suffix, this._unresolvedFilename), {
filename: this.filename,
displayErrors: false,
lineOffset: this.options.lineOffset || 0,
Expand All @@ -139,7 +153,7 @@ class VMScript {
if (this._compiledNodeVM) return this;

this._compiledNodeVM = new vm.Script('(function (exports, require, module, __filename, __dirname) { ' +
this._prefix + this._code + this._suffix + '\n})', {
this._compiler(this._prefix + this._code + this._suffix, this._unresolvedFilename) + '\n})', {
filename: this.filename,
displayErrors: false,
lineOffset: this.options.lineOffset || 0,
Expand Down Expand Up @@ -183,7 +197,7 @@ class VM extends EventEmitter {
this.options = {
timeout: options.timeout,
sandbox: options.sandbox,
compiler: options.compiler || 'javascript',
compiler: lookupCompiler(options.compiler || 'javascript'),
eval: options.eval === false ? false : true,
wasm: options.wasm === false ? false : true
};
Expand Down Expand Up @@ -281,15 +295,12 @@ class VM extends EventEmitter {
* Run the code in VM.
*
* @param {String} code Code to run.
* @param {String} [filename] Filename that shows up in any stack traces produced from this script.
* @return {*} Result of executed code.
*/

run(code) {
if (this.options.compiler !== 'javascript') {
code = _compileToJS(code, this.options.compiler);
}

const script = code instanceof VMScript ? code : new VMScript(code);
run(code, filename) {
const script = code instanceof VMScript ? code : new VMScript(code, filename, {compiler: this.options.compiler});
script._compileVM();

try {
Expand Down Expand Up @@ -330,7 +341,7 @@ class NodeVM extends EventEmitter {
sandbox: options.sandbox,
console: options.console || 'inherit',
require: options.require || false,
compiler: options.compiler || 'javascript',
compiler: lookupCompiler(options.compiler || 'javascript'),
eval: options.eval === false ? false : true,
wasm: options.wasm === false ? false : true,
nesting: options.nesting || false,
Expand Down Expand Up @@ -495,26 +506,23 @@ class NodeVM extends EventEmitter {
*/

run(code, filename) {
if (this.options.compiler !== 'javascript') {
code = _compileToJS(code, this.options.compiler, filename);
}

let dirname;
let returned;
let resolvedFilename;

if (filename) {
filename = pa.resolve(filename);
resolvedFilename = pa.resolve(filename);
dirname = pa.dirname(filename);
} else {
filename = null;
resolvedFilename = null;
dirname = null;
}

const module = SCRIPT_CACHE.exp._compiledVM.runInContext(this._context, {
displayErrors: false
});

const script = code instanceof VMScript ? code : new VMScript(code, filename);
const script = code instanceof VMScript ? code : new VMScript(code, resolvedFilename, {compiler: this.options.compiler, filename});
script._compileNodeVM();

try {
Expand Down
2 changes: 2 additions & 0 deletions test/vm.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,8 @@ describe('VM', () => {
return true;
});
}
assert.throws(() => new VM({compiler: 'nonexistant'}), /Unsupported compiler/);
assert.throws(() => new VMScript('', '', {compiler: 'nonexistant'}), /Unsupported compiler/);
});

it('timeout', () => {
Expand Down

0 comments on commit 78f8be5

Please sign in to comment.