"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = exports.JsSandbox = void 0;var fs = _interopRequireWildcard(require("fs"));
var path = _interopRequireWildcard(require("path"));
var vm = _interopRequireWildcard(require("vm"));
var _stream = require("stream");
var _util = require("util");

var babel = _interopRequireWildcard(require("@babel/core"));function _interopRequireWildcard(obj) {if (obj && obj.__esModule) {return obj;} else {var newObj = {};if (obj != null) {for (var key in obj) {if (Object.prototype.hasOwnProperty.call(obj, key)) {var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {};if (desc.get || desc.set) {Object.defineProperty(newObj, key, desc);} else {newObj[key] = obj[key];}}}}newObj.default = obj;return newObj;}}function _defineProperty(obj, key, value) {if (key in obj) {Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true });} else {obj[key] = value;}return obj;}

const presetEnv = require('@babel/preset-env');
const presetTypescript = require('@babel/preset-typescript');






const createProxies = (reporter, hash) => {
  const createWritable = name => {
    return new _stream.Writable({
      write: value => {
        reporter.output(hash, name, value);
      } });

  };
  const stdout = createWritable('stdout');
  const stderr = createWritable('stderr');

  const processProxy = new Proxy(process, {
    get: (target, name) => {
      switch (name) {
        case 'stdout':
          return stdout;
        case 'stderr':
          return stderr;
        default:
          return process[name].bind(process);}

    } });

  const consoleProxy = new Proxy(console, {
    get: (target, name) => {
      if (!(name in console)) {
        return undefined;
      }
      return (...args) => {
        // FIXME time系とか
        const format = value => {
          if (typeof value === 'string') {
            return value;
          } else {
            return (0, _util.inspect)(value, { colors: false });
          }
        };
        reporter.output(
        hash,
        name !== 'error' ? 'stdout' : 'stderr',
        `${args.map(arg => format(arg)).join(' ')}\n`);

      };
    } });


  return { processProxy, consoleProxy };
};

const createRequire = rootPath => {
  return name => {
    const validatePath = p => {
      if (p.startsWith(rootPath)) {
        return;
      }
      if (p.startsWith(path.resolve(path.join(__dirname, '..')))) {
        return;
      }

      throw new Error(`Sandbox Error: require ${name}`);
    };

    if (name.startsWith('./') || name.startsWith('../')) {
      const fullPath = require.resolve(name);
      validatePath(fullPath);
      return require(fullPath);
    }

    if (name.startsWith('/') || name.startsWith('.')) {
      throw new Error('Sandbox Error: Illegal path');
    }

    // FIXME: actual-code library
    // if (name === 'actual-code') {
    //   return actualCodeObject
    // }
    const fullpath = path.resolve(path.join(rootPath, 'node_modules', name));
    if (fs.existsSync(fullpath)) {
      validatePath(fullpath);
      return require(fullpath);
    } else {
      validatePath(require.resolve(name));
      return require(name);
    }
  };
};

class JsSandbox {












  constructor(reporter, rootPath) {_defineProperty(this, "rootPath", void 0);_defineProperty(this, "filetypes", { js: 'js', javascript: 'js', ts: 'ts', typescript: 'ts', jsx: 'jsx', tsx: 'tsx' });_defineProperty(this, "reporter", void 0);_defineProperty(this, "timeout", void 0);_defineProperty(this, "ctx", void 0);
    this.rootPath = rootPath;
    this.reporter = reporter;
    this.timeout = 100;

    const { consoleProxy, processProxy } = createProxies(reporter, null);
    const requireSandbox = createRequire(rootPath);
    this.ctx = {
      require: requireSandbox,
      setTimeout,
      setInterval,
      setImmediate,
      clearTimeout,
      clearInterval,
      clearImmediate,
      process: processProxy,
      Buffer,
      console: consoleProxy,
      exports: {} };

    vm.createContext(this.ctx);
  }

  async run(code, hash, lang, meta) {
    lang = this.filetypes[lang];
    if (!lang) {
      return false;
    }
    this.reporter.log(`run ${lang}`);
    try {
      const compiled = await babel.transformAsync(code, {
        ast: false,
        presets: [
        [
        presetEnv,
        {
          targets: {
            node: process.version,
            browsers: ['last 2 Chrome version'] } }],



        presetTypescript],

        sourceType: 'module',
        filename: `file.${lang}` });

      const timeout = meta.timeout || this.timeout;
      const { consoleProxy, processProxy } = createProxies(this.reporter, hash);
      this.ctx.console = consoleProxy;
      this.ctx.process = processProxy;
      vm.runInContext(compiled.code, this.ctx, { timeout });
    } catch (error) {
      this.reporter.output(hash, 'stderr', (0, _util.inspect)(error, { colors: false }));
    }
    return true;
  }}exports.JsSandbox = JsSandbox;


const plugin = () => {
  return {
    name: 'Node.js',
    sandbox: async (reporter, rootPath) => new JsSandbox(reporter, rootPath) };

};var _default =

plugin;exports.default = _default;