class JsDuck::Js::Class
Auto-detection of classes.
Public Instance Methods
Checks if AST node is a class, and if so, returns doc-hash with class name and various auto-detected attributes. When not a class returns nil.
# File lib/jsduck/js/class.rb, line 16 def detect(ast, docs) @docs = docs exp = ast.expression_statement? ? ast["expression"] : nil var = ast.variable_declaration? ? ast["declarations"][0] : nil # Ext.define("Class", {}) if exp && exp.ext_define? make(exp["arguments"][0].to_value, exp) # Ext.override(Class, {}) elsif exp && exp.ext_override? make("", exp) # foo = Ext.extend(Parent, {}) elsif exp && exp.assignment_expression? && exp["right"].ext_extend? make(exp["left"].to_s, exp["right"]) # Foo = ... elsif exp && exp.assignment_expression? && class_name?(exp["left"].to_s) make(exp["left"].to_s, exp["right"]) # var foo = Ext.extend(Parent, {}) elsif var && var["init"].ext_extend? make(var["id"].to_s, var["init"]) # var Foo = ... elsif var && class_name?(var["id"].to_s) make(var["id"].to_s, var["right"]) # function Foo() {} elsif ast.function? && class_name?(ast["id"].to_s || "") make(ast["id"].to_s) # { ... } elsif ast.object_expression? make("", ast) else nil end end
Produces a doc-hash for a class.
# File lib/jsduck/js/class.rb, line 60 def make(name, ast=nil) cls = { :tagname => :class, :name => name, } # apply information from Ext.extend, Ext.define, or {} if ast if ast.ext_define? detect_ext_define(cls, ast) elsif ast.ext_extend? detect_ext_something(:extends, cls, ast) elsif ast.ext_override? detect_ext_something(:override, cls, ast) elsif ast.object_expression? detect_class_members_from_object(cls, ast) elsif ast.array_expression? detect_class_members_from_array(cls, ast) end end return cls end
Private Instance Methods
Sets auto-detection related properties :autodetected and :inheritdoc on the given member Hash.
When member has a comment, adds code to the related docset and returns false.
Otherwise detects the line number of member and returns true.
# File lib/jsduck/js/class.rb, line 205 def apply_autodetected(m, ast, inheritable=true) docset = find_docset(ast.raw) if !docset || docset[:type] != :doc_comment if inheritable m[:inheritdoc] = {} else m[:private] = true end m[:autodetected] = {:tagname => m[:tagname]} end if docset docset[:code] = m return false else m[:linenr] = ast.linenr return true end end
Class
name begins with upcase char
# File lib/jsduck/js/class.rb, line 87 def class_name?(name) return name.split(/\./).last =~ /\A[A-Z]/ end
Detects class members from array literal
# File lib/jsduck/js/class.rb, line 148 def detect_class_members_from_array(cls, ast) cls[:members] = [] # This will most likely be an @enum class, in which case the # enum will be for documentation purposes only. cls[:enum] = {:doc_only => true} ast["elements"].each do |el| detect_method_or_property(cls, el.key_value, el, el) end end
Detects class members from object literal
# File lib/jsduck/js/class.rb, line 140 def detect_class_members_from_object(cls, ast) cls[:members] = [] ast.each_property do |key, value, pair| detect_method_or_property(cls, key, value, pair) if pair.raw["kind"] == "init" end end
Inspects Ext.define() and copies detected properties over to the given cls Hash
# File lib/jsduck/js/class.rb, line 103 def detect_ext_define(cls, ast) # defaults cls.merge!(Js::ExtDefine.defaults) cls[:members] = [] cls[:code_type] = :ext_define definition_node = ast["arguments"][1] # Support both function and object notation if definition_node.function_expression? definition_node = definition_node.return_statement_expression return if definition_node.nil? end definition_node.each_property do |key, value, pair| if tag = Js::ExtDefine.get_tag_by_pattern(key) tag.parse_ext_define(cls, value) else case key when "config" cls[:members] += make_configs(value, {:accessor => true}) when "cachedConfig" cls[:members] += make_configs(value, {:accessor => true}) when "eventedConfig" cls[:members] += make_configs(value, {:accessor => true, :evented => true}) when "statics" cls[:members] += make_statics(value) when "inheritableStatics" cls[:members] += make_statics(value, {:inheritable => true}) else detect_method_or_property(cls, key, value, pair) if pair.raw["kind"] == "init" end end end end
Detection of Ext.extend() or Ext.override(). The type parameter must be correspondingly either :extend or :override.
# File lib/jsduck/js/class.rb, line 93 def detect_ext_something(type, cls, ast) args = ast["arguments"] cls[type] = args[0].to_s if args.length == 2 && args[1].object_expression? detect_class_members_from_object(cls, args[1]) end end
Detects item in object literal either as method or property
# File lib/jsduck/js/class.rb, line 161 def detect_method_or_property(cls, key, value, pair) member = value.function? ? make_method(key, value) : make_property(key, value) cls[:members] << member if apply_autodetected(member, pair) end
Looks up docset associated with given AST node. A dead-stupid and -slow implementation, but works.
The comparison needs to be done between raw AST nodes - multiple Node
instances can be created to wrap a single raw AST node, and they will then not be equal.
# File lib/jsduck/js/class.rb, line 232 def find_docset(raw_ast) @docs.find do |docset| docset[:code] == raw_ast end end
# File lib/jsduck/js/class.rb, line 166 def make_configs(ast, defaults={}) configs = [] ast.each_property do |name, value, pair| cfg = make_property(name, value) cfg[:tagname] = :cfg cfg.merge!(defaults) configs << cfg if apply_autodetected(cfg, pair) end configs end
# File lib/jsduck/js/class.rb, line 238 def make_method(name, ast) Js::Method.make(name, ast) end
# File lib/jsduck/js/class.rb, line 242 def make_property(name=nil, ast=nil) Js::Property.make(name, ast) end
# File lib/jsduck/js/class.rb, line 179 def make_statics(ast, defaults={}) statics = [] ast.each_property do |name, value, pair| if value.function? s = make_method(name, value) else s = make_property(name, value) end s[:static] = true s.merge!(defaults) statics << s if apply_autodetected(s, pair, defaults[:inheritable]) end statics end