class SourceMap::Map

def self.decode_vlq_mappings(str, sources = [], names = [])

Returns an Array of Mappings.

names - Array of Strings from 'names' attribute
sources - Array of Strings from 'sources' attribute
str - VLQ string from 'mappings' attribute

Internal: Decode VLQ mappings and match up sources and symbol names.
def self.decode_vlq_mappings(str, sources = [], names = [])
  mappings = []
  source_id       = 0
  original_line   = 1
  original_column = 0
  name_id         = 0
  VLQ.decode_mappings(str).each_with_index do |group, index|
    generated_column = 0
    generated_line   = index + 1
    group.each do |segment|
      generated_column += segment[0]
      generated = Offset.new(generated_line, generated_column)
      if segment.size >= 4
        source_id        += segment[1]
        original_line    += segment[2]
        original_column  += segment[3]
        source   = sources[source_id]
        original = Offset.new(original_line, original_column)
      else
        # TODO: Research this case
        next
      end
      if segment[4]
        name_id += segment[4]
        name     = names[name_id]
      end
      mappings << Mapping.new(source, generated, original, name)
    end
  end
  mappings
end

def self.from_hash(hash)

def self.from_hash(hash)
  str     = hash['mappings']
  sources = hash['sources']
  names   = hash['names']
  mappings = decode_vlq_mappings(str, sources, names)
  new(mappings, hash['file'])
end

def self.from_json(json)

def self.from_json(json)
  from_hash JSON.parse(json)
end

def +(other)

def +(other)
  mappings = @mappings.dup
  offset   = @mappings.any? ? @mappings.last.generated.line+1 : 0
  other.each do |m|
    mappings << Mapping.new(
      m.source, m.generated + offset,
      m.original, m.name
    )
  end
  self.class.new(mappings, other.filename)
end

def ==(other)

def ==(other)
  eql?(other)
end

def [](i)

def [](i)
  @mappings[i]
end

def as_json(*)

def as_json(*)
  {
    "version"   => 3,
    "file"      => filename,
    "mappings"  => to_s,
    "sources"   => sources,
    "names"     => names
  }
end

def bsearch(offset, from = 0, to = size - 1)

def bsearch(offset, from = 0, to = size - 1)
  mid = (from + to) / 2
  # We haven't found a match
  if from > to
    return from < 1 ? nil : self[from-1]
  end
  # We found an exact match
  if offset == self[mid].generated
    self[mid]
  # We need to filter more
  elsif offset < self[mid].generated
    bsearch(offset, from, mid - 1)
  elsif offset > self[mid].generated
    bsearch(offset, mid + 1, to)
  end
end

def build_vlq_string

def build_vlq_string
  source_id        = 0
  source_line      = 1
  source_column    = 0
  name_id          = 0
  by_lines = @mappings.group_by { |m| m.generated.line }
  sources_index = Hash[sources.each_with_index.to_a]
  names_index   = Hash[names.each_with_index.to_a]
  ary = (1..(by_lines.keys.max || 1)).map do |line|
    generated_column = 0
    (by_lines[line] || []).map do |mapping|
      group = []
      group << mapping.generated.column - generated_column
      group << sources_index[mapping.source] - source_id
      group << mapping.original.line - source_line
      group << mapping.original.column - source_column
      group << names_index[mapping.name] - name_id if mapping.name
      generated_column = mapping.generated.column
      source_id        = sources_index[mapping.source]
      source_line      = mapping.original.line
      source_column    = mapping.original.column
      name_id          = names_index[mapping.name] if mapping.name
      group
    end
  end
  VLQ.encode_mappings(ary)
end

def each(&block)

def each(&block)
  @mappings.each(&block)
end

def eql?(other)

def eql?(other)
  other.is_a?(self.class) &&
    self.mappings == other.mappings &&
    self.filename == other.filename
end

def initialize(mappings = [], filename = nil)

def initialize(mappings = [], filename = nil)
  @mappings, @filename = mappings, filename
end

def inspect

Returns a String.

Public: Get a pretty inspect output for debugging purposes.
def inspect
  str = "#<#{self.class}"
  str << " filename=#{filename.inspect}" if filename
  str << " mappings=#{mappings.map(&:to_s).inspect}" if mappings.any?
  str << ">"
  str
end

def names

def names
  @names ||= @mappings.map(&:name).uniq.compact
end

def size

def size
  @mappings.size
end

def sources

def sources
  @sources ||= @mappings.map(&:source).uniq.compact
end

def to_json(*a)

def to_json(*a)
  as_json.to_json(*a)
end

def to_s

def to_s
  @string ||= build_vlq_string
end

def |(other)

def |(other)
  return other.dup if self.mappings.empty?
  mappings = []
  other.each do |m|
    om = bsearch(m.original)
    next unless om
    mappings << Mapping.new(
      om.source, m.generated,
      om.original, om.name
    )
  end
  self.class.new(mappings, other.filename)
end