Class: SourceMap::Map

Inherits:
Object show all
Includes:
Enumerable
Defined in:
opal/stdlib/source_map/map.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Enumerable

#to_json, #to_set

Constructor Details

#initialize(mappings = [], filename = nil) ⇒ Map

Returns a new instance of Map



71
72
73
# File 'opal/stdlib/source_map/map.rb', line 71

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

Instance Attribute Details

#filenameObject (readonly)

Returns the value of attribute filename



75
76
77
# File 'opal/stdlib/source_map/map.rb', line 75

def filename
  @filename
end

Class Method Details

.decode_vlq_mappings(str, sources = [], names = []) ⇒ Object

Internal: Decode VLQ mappings and match up sources and symbol names.

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

Returns an Array of Mappings.



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
# File 'opal/stdlib/source_map/map.rb', line 31

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

.from_hash(hash) ⇒ Object



15
16
17
18
19
20
21
22
# File 'opal/stdlib/source_map/map.rb', line 15

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

.from_json(json) ⇒ Object



11
12
13
# File 'opal/stdlib/source_map/map.rb', line 11

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

Instance Method Details

#+(other) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
# File 'opal/stdlib/source_map/map.rb', line 111

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

#==(other) ⇒ Object



101
102
103
# File 'opal/stdlib/source_map/map.rb', line 101

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

#[](i) ⇒ Object



81
82
83
# File 'opal/stdlib/source_map/map.rb', line 81

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

#as_jsonObject



161
162
163
164
165
166
167
168
169
# File 'opal/stdlib/source_map/map.rb', line 161

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

#bsearch(offset, from = 0, to = size - 1) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'opal/stdlib/source_map/map.rb', line 141

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

#each(&block) ⇒ Object



85
86
87
# File 'opal/stdlib/source_map/map.rb', line 85

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

#eql?(other) ⇒ Boolean

Returns:



105
106
107
108
109
# File 'opal/stdlib/source_map/map.rb', line 105

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

#inspectObject

Public: Get a pretty inspect output for debugging purposes.

Returns a String.



174
175
176
177
178
179
180
# File 'opal/stdlib/source_map/map.rb', line 174

def inspect
  str = "#<#{self.class}"
  str << " filename=#{filename.inspect}" if filename
  str << " mappings=#{mappings.map(&:to_s).inspect}" if mappings.any?
  str << ">"
  str
end

#namesObject



97
98
99
# File 'opal/stdlib/source_map/map.rb', line 97

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

#sizeObject



77
78
79
# File 'opal/stdlib/source_map/map.rb', line 77

def size
  @mappings.size
end

#sourcesObject



93
94
95
# File 'opal/stdlib/source_map/map.rb', line 93

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

#to_sObject



89
90
91
# File 'opal/stdlib/source_map/map.rb', line 89

def to_s
  @string ||= build_vlq_string
end

#|(other) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'opal/stdlib/source_map/map.rb', line 123

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