All files / lib/agents node.js

93.75% Statements 30/32
82.61% Branches 19/23
100% Functions 3/3
93.75% Lines 30/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111    1x 1x 1x 1x       40x                       40x                             40x                                 40x       40x       40x       40x 36x     40x       39x   39x 7x     32x 32x 32x   32x   32x 32x 32x 1x           31x 31x 1x               30x     1x   1x  
'use strict';
 
const fs = require('fs');
const runtimePath = require('../runtime-path');
const ConsoleAgent = require('../ConsoleAgent');
const ErrorParser = require('../parse-error');
 
class NodeAgent extends ConsoleAgent {
  compile(code) {
    code = super.compile(code);
 
    // `JSON.stringify` replaces BACKSPACE, CHARACTER TABULATION, LINE FEED
    // (LF), FORM FEED (FF), CARRIAGE RETURN (CR), QUOTATION MARK, and REVERSE
    // SOLIDUS [1]. This does not include two valid ECMAScript line
    // terminators: LINE SEPARATOR, and PARAGRAPH SEPARATOR [2]. Those two code
    // points must be explicitly escaped from the output of `JSON.stringify` so
    // that the source can be safely included in a dynamically-evaluated
    // string.
    //
    // [1] https://tc39.github.io/ecma262/#table-json-single-character-escapes
    // [2] https://tc39.github.io/ecma262/#table-33
    const escaped = JSON.stringify(code)
      .replace(/\u2028/g, '\\u2028')
      .replace(/\u2029/g, '\\u2029');
 
    // Because the input code may modify the global environment in ways that
    // interfere with the normal operation of `eshost`, it must be run in a
    // dedicated virtual machine.
    //
    // The "context" object for this virtual machine should be re-used if the
    // input code invokes `$.evalScript`, but Node.js does not tolerate sharing
    // context objects across virtual machines in this manner. Instead, define
    // a new method for evaluating scripts in the context created here.
    //
    // The "print" function is defined here, instead of runtimes/node.js because
    // not all code will be run with the entire host runtime.
    code = `
      Function("return this;")().require = require;
      var vm = require("vm");
      var eshostContext = vm.createContext({
        setTimeout,
        require,
        console,
        print(...args) {
          console.log(...args);
        }
      });
      vm.runInESHostContext = function(code, options) {
        return vm.runInContext(code, eshostContext, options);
      };
      vm.runInESHostContext(${escaped});
    `;
 
    return code;
  }
 
  async evalScript(code, options = {}) {
    Iif (options.module && this.args[0] !== '--experimental-modules') {
      this.args.unshift('--experimental-modules');
    }
 
    Iif (!options.module && this.args[0] === '--experimental-modules') {
      this.args.shift();
    }
 
    if (!this.args.includes('--expose-gc')) {
      this.args.push('--expose-gc');
    }
 
    return super.evalScript(code, options);
  }
 
  parseError(str) {
    let parsed = ErrorParser.parse(str);
 
    if (parsed) {
      return parsed;
    }
 
    const errorexp = /^[\w\d]+(:.*)?(?:(\r?\n\s+at.*)+|\r?\n$)/m;
    const nodeerrorexp = /^([\w\d]+)(?:\s+)(?:\{\s+message:\s+'(.*)'\s+\})/gm;
    const customerrorexp = /^(?:[\w\d]+)(?:\s+)(?:\{(?:\s+name:\s+'(.*)',\s+message:\s+'(.*)'\s+)\})/gm;
 
    let match = str.match(errorexp);
 
    Eif (!match) {
      match = nodeerrorexp.exec(str);
      if (match && match.length === 3) {
        return {
          name: match[1],
          message: match[2],
          stack: []
        };
      } else {
        match = customerrorexp.exec(str);
        if (match && match.length === 3) {
          return {
            name: match[1],
            message: match[2],
            stack: []
          };
        }
      }
    }
    return null;
  }
}
NodeAgent.runtime = fs.readFileSync(runtimePath.for('node'), 'utf8');
 
module.exports = NodeAgent;