Class: JsDuck::Aggregator

Inherits:
Object
  • Object
show all
Defined in:
lib/jsduck/aggregator.rb

Overview

Combines JavaScript Parser, DocParser and Merger. Produces array of classes as result.

Instance Method Summary collapse

Constructor Details

#initializeAggregator

Returns a new instance of Aggregator.



12
13
14
15
16
17
18
# File 'lib/jsduck/aggregator.rb', line 12

def initialize
  @documentation = []
  @classes = {}
  @alt_names = {}
  @orphans = []
  @current_class = nil
end

Instance Method Details

#add_class(cls) ⇒ Object

When class exists, merge it with class node. Otherwise add as new class.



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
# File 'lib/jsduck/aggregator.rb', line 43

def add_class(cls)
  old_cls = @classes[cls[:name]]
  if !old_cls && @alt_names[cls[:name]]
    old_cls = @alt_names[cls[:name]]
    warn_alt_name(cls)
  end

  if old_cls
    merge_classes(old_cls, cls)
    @current_class = old_cls
  else
    @current_class = cls
    @documentation << cls
    @classes[cls[:name]] = cls

    # Register all alternate names of class for lookup too
    cls[:alternateClassNames].each do |altname|
      if cls[:name] == altname
        # A buggy documentation, warn.
        warn_alt_name(cls)
      else
        @alt_names[altname] = cls
        # When an alternate name has been used as a class name before,
        # then this is one crappy documentation, but attempt to handle
        # it by merging the class with alt-name into this class.
        if @classes[altname]
          merge_classes(cls, @classes[altname])
          @documentation.delete(@classes[altname])
          @classes.delete(altname)
          warn_alt_name(cls)
        end
      end
    end

    insert_orphans(cls)
  end
end

#add_empty_class(name, doc = "") ⇒ Object



185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/jsduck/aggregator.rb', line 185

def add_empty_class(name, doc = "")
  add_class({
    :tagname => :class,
    :name => name,
    :doc => doc,
    :mixins => [],
    :alternateClassNames => [],
    :members => [],
    :aliases => {},
    :meta => {},
    :files => [{:filename => "", :linenr => 0, :href => ""}],
  })
end

#add_member(node) ⇒ Object

Tries to place members into classes where they belong.

item with @member=Foo before we actually meet class Foo - in that case we register them as orphans. (Later when we finally meet class Foo, orphans are inserted into it.)

Items without @member belong by default to the preceding class. When no class precedes them - they too are orphaned.



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/jsduck/aggregator.rb', line 121

def add_member(node)
  # Completely ignore member if @ignore used
  return if node[:meta][:ignore]

  if node[:owner]
    if @classes[node[:owner]]
      add_to_class(@classes[node[:owner]], node)
    else
      add_orphan(node)
    end
  elsif @current_class
    node[:owner] = @current_class[:name]
    add_to_class(@current_class, node)
  else
    add_orphan(node)
  end
end

#add_orphan(node) ⇒ Object



143
144
145
# File 'lib/jsduck/aggregator.rb', line 143

def add_orphan(node)
  @orphans << node
end

#add_to_class(cls, member) ⇒ Object



139
140
141
# File 'lib/jsduck/aggregator.rb', line 139

def add_to_class(cls, member)
  cls[:members] << member
end

#aggregate(file) ⇒ Object

Combines chunk of parsed JavaScript together with previously added chunks. The resulting documentation is accumulated inside this class and can be later accessed through #result method.

  • file SoureFile class instance



26
27
28
29
# File 'lib/jsduck/aggregator.rb', line 26

def aggregate(file)
  @current_class = nil
  file.each {|doc| register(doc) }
end

#append_ext4_event_optionsObject

Appends Ext4 options parameter to each event parameter list.



210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/jsduck/aggregator.rb', line 210

def append_ext4_event_options
  options = {
    :tagname => :param,
    :name => "eOpts",
    :type => "Object",
    :doc => "The options object passed to {@link Ext.util.Observable#addListener}."
  }
  @classes.each_value do |cls|
    cls[:members].each do |m|
      m[:params] << options if m[:tagname] == :event
    end
  end
end

#classify_orphansObject

Creates classes for orphans that have :owner property defined, and then inserts orphans to these classes.



158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/jsduck/aggregator.rb', line 158

def classify_orphans
  # Clone the orphans array first to avoid problems with
  # #inster_orphan method deleting items from @orphans array.
  @orphans.clone.each do |orph|
    if orph[:owner]
      class_name = orph[:owner]
      if !@classes[class_name]
        # this will add the class and add all orphans to it
        add_empty_class(class_name)
      end
    end
  end
end

#create_accessorsObject

Creates accessor method for configs marked with @accessor



225
226
227
228
229
230
# File 'lib/jsduck/aggregator.rb', line 225

def create_accessors
  accessors = Accessors.new
  @classes.each_value do |cls|
    accessors.create(cls)
  end
end

#create_global_classObject

Creates class with name “global” and inserts all the remaining orphans into it (but only if there are any orphans).



174
175
176
177
178
179
180
181
182
183
# File 'lib/jsduck/aggregator.rb', line 174

def create_global_class
  return if @orphans.length == 0

  add_empty_class("global", "Global variables and functions.")
  @orphans.each do |orph|
    orph[:owner] = "global"
    add_member(orph)
  end
  @orphans = []
end

#ext4?Boolean

Are we dealing with ExtJS 4? True if any of the classes is defined with Ext.define()

Returns:

  • (Boolean)


250
251
252
# File 'lib/jsduck/aggregator.rb', line 250

def ext4?
  @documentation.any? {|cls| cls[:code_type] == :ext_define }
end

#insert_orphans(cls) ⇒ Object

Inserts available orphans to class



148
149
150
151
152
153
154
# File 'lib/jsduck/aggregator.rb', line 148

def insert_orphans(cls)
  members = @orphans.find_all {|node| node[:owner] == cls[:name] }
  members.each do |node|
    add_to_class(cls, node)
    @orphans.delete(node)
  end
end

#merge_classes(old, new) ⇒ Object

Merges new class-doc into old one.



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/jsduck/aggregator.rb', line 88

def merge_classes(old, new)
  # Merge booleans
  [:extends, :singleton, :private].each do |tag|
    old[tag] = old[tag] || new[tag]
  end
  # Merge arrays
  [:mixins, :alternateClassNames, :files].each do |tag|
    old[tag] = old[tag] + new[tag]
  end
  # Merge meta hashes
  new[:meta].each_pair do |name, value|
    old[:meta][name] = old[:meta][name] || value
  end
  # Merge hashes of arrays
  [:aliases].each do |tag|
    new[tag].each_pair do |key, contents|
      old[tag][key] = (old[tag][key] || []) + contents
    end
  end
  old[:doc] = old[:doc].length > 0 ? old[:doc] : new[:doc]
  # Additionally the doc-comment can contain configs and constructor
  old[:members] += new[:members]
end

#process_enumsObject

Loops through all enums and auto-detects their types if needed.



233
234
235
# File 'lib/jsduck/aggregator.rb', line 233

def process_enums
  Enum.new(@classes).process_all!
end

#process_overridesObject

Processes all overrides. Returns list of override classes.



239
240
241
242
243
244
245
246
# File 'lib/jsduck/aggregator.rb', line 239

def process_overrides
  Override.new(@classes).process_all!.map do |cls|
    # discard each override class
    @classes.delete(cls[:name])
    @documentation.delete(cls)
    cls
  end
end

#register(node) ⇒ Object

Registers documentation node either as class or as member of some class.



33
34
35
36
37
38
39
# File 'lib/jsduck/aggregator.rb', line 33

def register(node)
  if node[:tagname] == :class
    add_class(node)
  else
    add_member(node)
  end
end

#remove_ignored_classesObject

Gets rid of classes marked with @ignore



200
201
202
203
204
205
206
207
# File 'lib/jsduck/aggregator.rb', line 200

def remove_ignored_classes
  @documentation.delete_if do |cls|
    if cls[:meta][:ignore]
      @classes.delete(cls["name"])
      true
    end
  end
end

#resultObject



254
255
256
# File 'lib/jsduck/aggregator.rb', line 254

def result
  @documentation + @orphans
end

#warn_alt_name(cls) ⇒ Object



81
82
83
84
85
# File 'lib/jsduck/aggregator.rb', line 81

def warn_alt_name(cls)
  file = cls[:files][0][:filename]
  line = cls[:files][0][:linenr]
  Logger.warn(:alt_name, "Name #{cls[:name]} used as both classname and alternate classname", file, line)
end