class JsDuck::Process::InheritMembers
Deals with inheriting member documentation.
Public Class Methods
# File lib/jsduck/process/inherit_members.rb, line 9 def initialize(relations) @relations = relations end
Public Instance Methods
Inherits docs for all members in class.
In case of members with explicit @inheritdoc tags we inherit the following fields when they're not empty in current member:
-
:doc
-
:params
-
:return
-
:throws
-
:properties
In case of auto-detected members that inherit from a public member in parent class, we inherit all fields that aren't present in current member, plus the :type field.
Auto-detected members inheriting from other private auto-detected members follow the same rules of inheritance as members with explicit @inheritdoc.
Additionally auto-detected properties get turned into configs when a public configs with same name is detected in parent class.
# File lib/jsduck/process/inherit_members.rb, line 36 def resolve(cls) new_cfgs = [] cls.all_local_members.each do |member| if member[:inheritdoc] resolve_member(cls, member, new_cfgs) end end move_cfgs(cls, new_cfgs) if new_cfgs.length > 0 end
Private Instance Methods
True when specific field of member has been auto-detected
# File lib/jsduck/process/inherit_members.rb, line 124 def auto?(m, key) m[:autodetected] && m[:autodetected][key] end
# File lib/jsduck/process/inherit_members.rb, line 111 def auto_inherit(m, parent) m[:doc] = parent[:doc] if m[:doc].empty? parent.each_pair do |key, value| if key == :overrides # overrides can't be inherited. elsif key == :type || !m[key] m[key] = value end end end
True when the entire member was auto-detected
# File lib/jsduck/process/inherit_members.rb, line 243 def autodetected?(m) m[:autodetected] && m[:autodetected][:tagname] end
Finds parent member of the given member. When @inheritdoc names a member to inherit from, finds that member instead.
If the parent also has @inheritdoc, continues recursively.
# File lib/jsduck/process/inherit_members.rb, line 151 def find_parent(m) inherit = m[:inheritdoc] || {} if inherit[:cls] # @inheritdoc MyClass#member parent_cls = @relations[m[:inheritdoc][:cls]] return warn("class not found", m) unless parent_cls parent = lookup_member(parent_cls, m) return warn("member not found", m) unless parent elsif inherit[:member] # @inheritdoc #member parent = lookup_member(@relations[m[:owner]], m) return warn("member not found", m) unless parent else # @inheritdoc parent_cls = @relations[m[:owner]].parent mixins = @relations[m[:owner]].mixins # Warn when no parent or mixins at all if !parent_cls && mixins.length == 0 warn("parent class not found", m) unless autodetected?(m) return nil end # First check for the member in all mixins, because members # from mixins override those from parent class. Looking first # from mixins is probably a bit slower, but it's the correct # order to do things. if mixins.length > 0 parent = mixins.map {|mix| lookup_member(mix, m) }.compact.first end # When not found, try looking from parent class if !parent && parent_cls parent = lookup_member(parent_cls, m) end # Only when both parent and mixins fail, throw warning if !parent warn("parent member not found", m) unless autodetected?(m) return nil end end return parent end
# File lib/jsduck/process/inherit_members.rb, line 80 def inherit(m, parent) m[:doc] = parent[:doc] if m[:doc].empty? m[:params] = parent[:params] if inherit_params?(m, parent) m[:return] = parent[:return] unless m[:return] m[:throws] = parent[:throws] unless m[:throws] && m[:throws].length > 0 m[:properties] = parent[:properties] unless m[:properties] && m[:properties].length > 0 # Don't inherit type from parent when: # - member itself has type and it's not auto-detected # - or the type in parent is auto-detected. unless m[:type] && m[:type] != "Object" && !auto?(m, :type) || auto?(parent, :type) m[:type] = parent[:type] end end
# File lib/jsduck/process/inherit_members.rb, line 96 def inherit_params?(m, parent) # ignore the auto-inserted param of Ext4-style events params = (m[:params] || []).reject {|p| p[:ext4_auto_param] } if params.length > 0 && !auto?(m, :params) # member itself has params and these are not auto-detected false elsif auto?(parent, :params) # Params in parent are auto-detected. false else true end end
# File lib/jsduck/process/inherit_members.rb, line 201 def lookup_member(cls, m) inherit = m[:inheritdoc] || {} name = inherit[:member] || m[:name] tagname = inherit[:type] || m[:tagname] # When not explicitly inheriting from static member # and the member itself is not static, # inherit from instance member. static = inherit[:static] || m[:static] || false if autodetected?(m) # Auto-detected properties can override either a property or a # config. So look for both types. if tagname == :property cfg = cls.find_members(:name => name, :tagname => :cfg, :static => static)[0] prop = cls.find_members(:name => name, :tagname => :property, :static => static)[0] if cfg && prop prop elsif cfg cfg elsif prop prop else nil end else cls.find_members(:name => name, :tagname => tagname, :static => static)[0] end else m = cls.find_members(:name => name, :tagname => tagname, :static => static)[0] # When member was not found with explicit staticality and # the @inheritdoc tag contained no explicit "static", then # look for both static and instance members. if !m && !inherit[:static] m = cls.find_members(:name => name, :tagname => tagname, :static => nil)[0] end m end end
Changes given properties into configs within class
# File lib/jsduck/process/inherit_members.rb, line 129 def move_cfgs(cls, members) members.each do |m| m[:tagname] = :cfg end end
# File lib/jsduck/process/inherit_members.rb, line 50 def resolve_member(cls, m, new_cfgs) parent = find_parent(m) if parent && parent[:inheritdoc] resolve_parent(cls, parent) end if m[:inheritdoc] && parent if autodetected?(m) && !parent[:private] auto_inherit(m, parent) else inherit(m, parent) end # remember properties that have changed to configs if autodetected?(m) && m[:tagname] != parent[:tagname] new_cfgs << m end end resolve_visibility(m, parent) m[:inheritdoc] = nil end
# File lib/jsduck/process/inherit_members.rb, line 74 def resolve_parent(cls, parent) new_cfgs = [] resolve_member(cls, parent, new_cfgs) move_cfgs(cls, new_cfgs) if new_cfgs.length > 0 end
For auto-detected members/classes (which have @private == :inherit) Use the visibility from parent class (defaulting to private when no parent).
# File lib/jsduck/process/inherit_members.rb, line 137 def resolve_visibility(m, parent) if autodetected?(m) && !JsDuck::Class.constructor?(m) if !parent || parent[:private] m[:private] = true end m[:protected] = true if parent && parent[:protected] end end
# File lib/jsduck/process/inherit_members.rb, line 247 def warn(msg, m) inh_member = m[:inheritdoc][:member] inh_target = (m[:inheritdoc][:cls] || "") + (inh_member ? "#" + inh_member : "") Logger.warn(:inheritdoc, "@inheritdoc #{inh_target} - #{msg}", m[:files][0]) return nil end