lib/asciidoctor/opal_ext/file.rb



class Kernel
  # basic implementation of open, enough to work
  # with reading files over XmlHttpRequest
  def open(path, *rest)
    file = File.new(path, *rest)
    if block_given?
      yield file
    else
      file
    end
  end
end

class File
  SEPARATOR = '/'
  ALT_SEPARATOR = nil

  attr_reader :eof
  attr_reader :lineno
  attr_reader :path

  def initialize(path, mode = 'r')
    @path = path
    @contents = nil
    @eof = false
    @lineno = 0
  end

  def read
    if @eof
      ''
    else
      res = File.read(@path)
      @eof = true
      @lineno = res.size
      res
    end
  end

  def each_line(separator = $/, &block)
    if @eof
      return block_given? ? self : [].to_enum
    end

    if block_given?
      lines = File.read(@path)
      %x(
        self.eof = false;
        self.lineno = 0; 
        var chomped  = #{lines.chomp},
            trailing = lines.length != chomped.length,
            splitted = chomped.split(separator);

        for (var i = 0, length = splitted.length; i < length; i++) {
          self.lineno += 1;
          if (i < length - 1 || trailing) {
            #{yield `splitted[i] + separator`};
          }
          else {
            #{yield `splitted[i]`};
          }
        }
        self.eof = true;
      )
      self
    else
      read.each_line
    end
  end

  def self.expand_path(path)
    path
  end

  def self.join(*paths)
    paths * SEPARATOR
  end

  def self.basename(path)
    (offset = path.rindex SEPARATOR) ? path[(offset + 1)..-1] : path
  end

  def self.dirname(path)
    (offset = path.rindex SEPARATOR) ? path[0..(offset - 1)] : '.'
  end

  def self.extname(path)
    return '' if path.nil_or_empty?
    last_dot_idx = path[1..-1].rindex('.')
    last_dot_idx.nil? ? '' : path[(last_dot_idx + 1)..-1]
  end

  # TODO use XMLHttpRequest HEAD request unless in local file mode
  def self.file?(path)
    true
  end
  
  def self.read(path)
    case JAVASCRIPT_PLATFORM
    when 'node'
      %x(return require('fs').readFileSync(path, 'utf8');)
    when 'java-nashorn'
      %x(
        var Paths = Java.type('java.nio.file.Paths');
        var Files = Java.type('java.nio.file.Files');
        var lines = Files.readAllLines(Paths.get(path), Java.type('java.nio.charset.StandardCharsets').UTF_8);
        var data = [];
        lines.forEach(function(line) { data.push(line); });
        return data.join("\n");
      )
    #when 'java-rhino'
    when 'browser'
      %x(
        var data = '';
        var status = -1;
        try {
          var xhr = new XMLHttpRequest();
          xhr.open('GET', path, false);
          xhr.addEventListener('load', function() {
            status = this.status;
            // status is 0 for local file mode (i.e., file://)
            if (status == 0 || status == 200) {
              data = this.responseText;
            }
          });
          xhr.overrideMimeType('text/plain');
          xhr.send();
        }
        catch (e) {
          status = 0;
        }
        // assume that no data in local file mode means it doesn't exist
        if (status == 404 || (status == 0 && data == '')) {
          throw #{IOError.new `'No such file or directory: ' + path`};
        }
        return data;
      )
    # NOTE we're assuming standalone is SpiderMonkey
    when 'standalone'
      %x(return read(path);)
    else
      ''
    end
  end
end