jsduck 5.0.0.beta2 → 5.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/Rakefile +14 -4
  2. data/bin/jsduck +3 -1
  3. data/jsduck.gemspec +2 -2
  4. data/lib/jsduck/app.rb +8 -0
  5. data/lib/jsduck/assets.rb +3 -0
  6. data/lib/jsduck/batch_processor.rb +2 -0
  7. data/lib/jsduck/categories/class_name.rb +2 -26
  8. data/lib/jsduck/categories/factory.rb +5 -43
  9. data/lib/jsduck/columns.rb +56 -0
  10. data/lib/jsduck/doc/delimited_parser.rb +105 -0
  11. data/lib/jsduck/doc/scanner.rb +2 -1
  12. data/lib/jsduck/doc/standard_tag_parser.rb +37 -71
  13. data/lib/jsduck/guide_anchors.rb +32 -0
  14. data/lib/jsduck/guide_toc.rb +49 -0
  15. data/lib/jsduck/guides.rb +14 -32
  16. data/lib/jsduck/inline/video.rb +2 -8
  17. data/lib/jsduck/js/ast.rb +13 -305
  18. data/lib/jsduck/js/class.rb +245 -0
  19. data/lib/jsduck/js/event.rb +34 -0
  20. data/lib/jsduck/js/fires.rb +42 -0
  21. data/lib/jsduck/js/method.rb +94 -0
  22. data/lib/jsduck/js/method_calls.rb +40 -0
  23. data/lib/jsduck/js/node.rb +29 -0
  24. data/lib/jsduck/js/property.rb +64 -0
  25. data/lib/jsduck/js/{function.rb → returns.rb} +8 -3
  26. data/lib/jsduck/js/scoped_traverser.rb +42 -0
  27. data/lib/jsduck/logger.rb +13 -1
  28. data/lib/jsduck/merger.rb +34 -27
  29. data/lib/jsduck/news.rb +128 -0
  30. data/lib/jsduck/options.rb +59 -2
  31. data/lib/jsduck/params_merger.rb +47 -0
  32. data/lib/jsduck/process/accessors.rb +8 -2
  33. data/lib/jsduck/process/fires.rb +71 -0
  34. data/lib/jsduck/process/importer.rb +19 -1
  35. data/lib/jsduck/render/class.rb +11 -4
  36. data/lib/jsduck/render/signature_util.rb +14 -0
  37. data/lib/jsduck/tag/alias.rb +0 -20
  38. data/lib/jsduck/tag/alternate_class_names.rb +0 -5
  39. data/lib/jsduck/tag/cfg.rb +30 -5
  40. data/lib/jsduck/tag/class.rb +45 -2
  41. data/lib/jsduck/tag/css_mixin.rb +8 -4
  42. data/lib/jsduck/tag/css_var.rb +26 -5
  43. data/lib/jsduck/tag/default.rb +2 -8
  44. data/lib/jsduck/tag/enum.rb +7 -10
  45. data/lib/jsduck/tag/event.rb +12 -4
  46. data/lib/jsduck/tag/extends.rb +0 -6
  47. data/lib/jsduck/tag/fires.rb +53 -0
  48. data/lib/jsduck/tag/icons/cfg.png +0 -0
  49. data/lib/jsduck/tag/icons/css_mixin.png +0 -0
  50. data/lib/jsduck/tag/icons/css_var.png +0 -0
  51. data/lib/jsduck/tag/icons/event.png +0 -0
  52. data/lib/jsduck/tag/icons/method.png +0 -0
  53. data/lib/jsduck/tag/icons/property.png +0 -0
  54. data/lib/jsduck/tag/member_tag.rb +130 -0
  55. data/lib/jsduck/tag/method.rb +44 -4
  56. data/lib/jsduck/tag/param.rb +8 -60
  57. data/lib/jsduck/tag/property.rb +28 -5
  58. data/lib/jsduck/tag/tag.rb +3 -75
  59. data/lib/jsduck/tag/type.rb +1 -11
  60. data/lib/jsduck/tag_registry.rb +6 -48
  61. data/lib/jsduck/web/css.rb +8 -1
  62. data/lib/jsduck/web/data.rb +2 -1
  63. data/lib/jsduck/web/index_html.rb +1 -0
  64. data/lib/jsduck/web/member_icons.rb +43 -0
  65. data/lib/jsduck/web/search.rb +3 -2
  66. data/lib/jsduck/web/writer.rb +8 -0
  67. metadata +31 -27
  68. data/lib/jsduck/docs_code_comparer.rb +0 -44
  69. data/lib/jsduck/render/signature.rb +0 -94
  70. data/lib/jsduck/tag/autodetected.rb +0 -21
  71. data/lib/jsduck/tag/name.rb +0 -36
@@ -0,0 +1,47 @@
1
+ require "jsduck/logger"
2
+ require "jsduck/merger"
3
+
4
+ module JsDuck
5
+ # Performs the merging of :params field.
6
+ # Used by Method, Event and CssMixin members.
7
+ class ParamsMerger
8
+ # Ensures the existance of params array.
9
+ # Defaults type of each parameter to "Object".
10
+ # Logs warnings for inconsistencies between params in code and in docs.
11
+ def self.merge(h, docs, code)
12
+ h[:params] = [] unless h[:params]
13
+
14
+ h[:params].each do |p|
15
+ p[:type] = "Object" unless p[:type]
16
+ end
17
+
18
+ check_consistency(docs, code, h[:files].first)
19
+ end
20
+
21
+ def self.check_consistency(docs, code, file)
22
+ explicit = docs[:params] || []
23
+ implicit = JsDuck::Merger.can_be_autodetected?(docs, code) ? (code[:params] || []) : []
24
+ ex_len = explicit.length
25
+ im_len = implicit.length
26
+
27
+ if ex_len == 0 || im_len == 0
28
+ # Skip when either no implicit or explicit params
29
+ elsif ex_len != im_len && explicit.last[:type] =~ /\.\.\.$/
30
+ # Skip when vararg params are in play.
31
+ elsif ex_len < im_len
32
+ # Warn when less parameters documented than found from code.
33
+ JsDuck::Logger.warn(:param_count, "Detected #{im_len} params, but only #{ex_len} documented.", file)
34
+ elsif ex_len > im_len
35
+ # Warn when more parameters documented than found from code.
36
+ JsDuck::Logger.warn(:param_count, "Detected #{im_len} params, but #{ex_len} documented.", file)
37
+ elsif implicit.map {|p| p[:name] } != explicit.map {|p| p[:name] }
38
+ # Warn when parameter names don't match up.
39
+ ex_names = explicit.map {|p| p[:name] }
40
+ im_names = implicit.map {|p| p[:name] }
41
+ str = ex_names.zip(im_names).map {|p| ex, im = p; ex == im ? ex : (ex||"")+"/"+(im||"") }.join(", ")
42
+ JsDuck::Logger.warn(:param_count, "Documented and auto-detected params don't match: #{str}", file)
43
+ end
44
+ end
45
+
46
+ end
47
+ end
@@ -127,9 +127,15 @@ module JsDuck
127
127
  end
128
128
 
129
129
  # Copy over from @cfg all the fields that aren't already present.
130
- # Except :type and :default which don't make sense for methods and events.
131
130
  def add_shared(hash, cfg)
132
- ignored_fields = [:type, :default, :accessor, :evented]
131
+ ignored_fields = [
132
+ # These don't make sense for methods and events.
133
+ :type, :default,
134
+ # It's the config that's tagged with these, don't propagate them to methods/events.
135
+ :accessor, :evented,
136
+ # The :doc field get auto-created and we don't want any other docs.
137
+ :inheritdoc, :localdoc,
138
+ ]
133
139
 
134
140
  cfg.each_pair do |key, value|
135
141
  hash[key] = value unless ignored_fields.include?(key) || hash[key]
@@ -0,0 +1,71 @@
1
+ require 'jsduck/logger'
2
+
3
+ module JsDuck
4
+ module Process
5
+
6
+ # Expands lists of fired events to take into account events fired
7
+ # by all the methods that get called by a method.
8
+ class Fires
9
+ def initialize(relations)
10
+ @relations = relations
11
+ # Map of methods for which all @fires tags have been detected.
12
+ # So we don't repeat the resolving.
13
+ @detected = {}
14
+ # Map of methods that we're currently resolving.
15
+ # So we don't recurse into infinity.
16
+ @call_chain = {}
17
+ end
18
+
19
+ # Populates @fires tags with additional events.
20
+ def process_all!
21
+ @relations.each do |cls|
22
+ cls.find_members(:tagname => :method, :static => false).each do |m|
23
+ @call_chain = {m[:name] => true}
24
+ detect_fires(cls, m)
25
+ end
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def detect_fires(cls, m)
32
+ if m[:autodetected][:fires] && m[:method_calls] && !detected?(m)
33
+ m[:fires] = events_from_methods(cls, m[:method_calls]).concat(m[:fires] || []).sort.uniq
34
+ mark_detected(m)
35
+ end
36
+
37
+ m[:fires]
38
+ end
39
+
40
+ def mark_detected(m)
41
+ @detected[m[:owner]] = {} unless @detected[m[:owner]]
42
+ @detected[m[:owner]][m[:name]] = true
43
+ end
44
+
45
+ def detected?(m)
46
+ cls = @detected[m[:owner]]
47
+ cls && cls[m[:name]]
48
+ end
49
+
50
+ def events_from_methods(cls, methods)
51
+ events = []
52
+
53
+ methods.each do |name|
54
+ if !@call_chain[name]
55
+ @call_chain[name] = true
56
+ m = cls.find_members(:tagname => :method, :name => name, :static => false)[0]
57
+ if m
58
+ fires = detect_fires(cls, m)
59
+ events.concat(fires) if fires
60
+ end
61
+ @call_chain[name] = false
62
+ end
63
+ end
64
+
65
+ events.sort.uniq
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+ end
@@ -28,9 +28,11 @@ module JsDuck
28
28
 
29
29
  # Reads in data from all .json files in directory
30
30
  def read(ver)
31
+ ensure_correct_format(ver[:path])
32
+
31
33
  # Map list of files into pairs of (classname, members-hash)
32
34
  pairs = Util::Parallel.map(Dir[ver[:path] + "/*.json"]) do |filename|
33
- JsDuck::Logger.log("Importing #{ver[:version]}", filename)
35
+ Logger.log("Importing #{ver[:version]}", filename)
34
36
  json = Util::Json.read(filename)
35
37
  [json["name"], members_id_index(json)]
36
38
  end
@@ -39,6 +41,22 @@ module JsDuck
39
41
  return Hash[ pairs ]
40
42
  end
41
43
 
44
+ def ensure_correct_format(path)
45
+ # Read first JSON file in import dir
46
+ json = Util::Json.read(Dir[path + "/*.json"].first)
47
+
48
+ unless correct_format?(json)
49
+ Logger.fatal("Bad format for importing: #{path}")
50
+ Logger.fatal("Export format changed in 5.0.0 beta 2.")
51
+ Logger.fatal("Maybe you forgot to re-generate the exports with new JSDuck.")
52
+ exit(1)
53
+ end
54
+ end
55
+
56
+ def correct_format?(json)
57
+ json["members"].is_a?(Array)
58
+ end
59
+
42
60
  # creates index of all class members
43
61
  def members_id_index(json)
44
62
  index = {}
@@ -1,6 +1,6 @@
1
- require 'jsduck/render/signature'
2
1
  require 'jsduck/render/tags'
3
2
  require 'jsduck/render/sidebar'
3
+ require 'jsduck/tag_registry'
4
4
 
5
5
  module JsDuck
6
6
  module Render
@@ -13,7 +13,6 @@ module JsDuck
13
13
 
14
14
  def render(cls)
15
15
  @cls = cls
16
- @signature = Render::Signature.new(cls)
17
16
 
18
17
  return [
19
18
  "<div>",
@@ -122,8 +121,8 @@ module JsDuck
122
121
  "<br/>",
123
122
  @opts.source ? "<a href='source/#{m[:files][0][:href]}' target='_blank' class='view-source'>view source</a>" : "",
124
123
  "</div>",
125
- # method params signature or property type signature
126
- @signature.render(m),
124
+ render_member_signature(m),
125
+ render_tag_signature(m),
127
126
  "</div>",
128
127
  # short and long descriptions
129
128
  "<div class='description'>",
@@ -138,6 +137,14 @@ module JsDuck
138
137
  ]
139
138
  end
140
139
 
140
+ def render_member_signature(m)
141
+ TagRegistry.get_by_name(m[:tagname]).to_html(m, @cls)
142
+ end
143
+
144
+ def render_tag_signature(m)
145
+ Render::Tags.render_signature(m)
146
+ end
147
+
141
148
  end
142
149
 
143
150
  end
@@ -0,0 +1,14 @@
1
+ module JsDuck
2
+ module Render
3
+
4
+ # Helper method for rendering the link in method/property signature
5
+ class SignatureUtil
6
+
7
+ def self.link(class_name, member_id, text)
8
+ "<a href='#!/api/#{class_name}-#{member_id}' class='name expandable'>#{text}</a>"
9
+ end
10
+
11
+ end
12
+
13
+ end
14
+ end
@@ -9,7 +9,6 @@ module JsDuck::Tag
9
9
  @repeatable = true
10
10
  @ext_define_pattern = "alias"
11
11
  @ext_define_default = {:aliases => []}
12
- @merge_context = :class
13
12
  end
14
13
 
15
14
  # For backwards compatibility decide whether the @alias was used
@@ -39,24 +38,5 @@ module JsDuck::Tag
39
38
  cls[:aliases] += JsDuck::Js::Utils.make_string_list(ast)
40
39
  end
41
40
 
42
- def merge(h, docs, code)
43
- h[:aliases] = build_aliases_hash(docs[:aliases] || code[:aliases] || [])
44
- end
45
-
46
- # Given array of full alias names like "foo.bar", "foo.baz"
47
- # build hash like {"foo" => ["bar", "baz"]}
48
- def build_aliases_hash(aliases)
49
- hash={}
50
- aliases.each do |a|
51
- if a =~ /^([^.]+)\.(.+)$/
52
- if hash[$1]
53
- hash[$1] << $2
54
- else
55
- hash[$1] = [$2]
56
- end
57
- end
58
- end
59
- hash
60
- end
61
41
  end
62
42
  end
@@ -8,11 +8,6 @@ module JsDuck::Tag
8
8
  @repeatable = true
9
9
  @ext_define_pattern = "alternateClassName"
10
10
  @ext_define_default = {:alternateClassNames => []}
11
- @merge_context = :class
12
- end
13
-
14
- def merge(h, docs, code)
15
- h[@tagname] = docs[@tagname] || code[@tagname] || []
16
11
  end
17
12
  end
18
13
  end
@@ -1,18 +1,17 @@
1
- require "jsduck/tag/tag"
1
+ require "jsduck/tag/member_tag"
2
2
  require "jsduck/doc/subproperties"
3
3
 
4
4
  module JsDuck::Tag
5
- class Cfg < Tag
5
+ class Cfg < MemberTag
6
6
  def initialize
7
7
  @pattern = "cfg"
8
8
  @tagname = :cfg
9
9
  @repeatable = true
10
10
  @member_type = {
11
- :name => :cfg,
12
- :category => :property_like,
13
11
  :title => "Config options",
14
12
  :toolbar_title => "Configs",
15
13
  :position => MEMBER_POS_CFG,
14
+ :icon => File.dirname(__FILE__) + "/icons/cfg.png",
16
15
  :subsections => [
17
16
  {:title => "Required config options", :filter => {:required => true}},
18
17
  {:title => "Optional config options", :filter => {:required => false}, :default => true},
@@ -22,7 +21,13 @@ module JsDuck::Tag
22
21
 
23
22
  # @cfg {Type} [name=default] (required) ...
24
23
  def parse_doc(p, pos)
25
- tag = p.standard_tag({:tagname => :cfg, :type => true, :name => true})
24
+ tag = p.standard_tag({
25
+ :tagname => :cfg,
26
+ :type => true,
27
+ :name => true,
28
+ :default => true,
29
+ :optional => true
30
+ })
26
31
  tag[:optional] = false if parse_required(p)
27
32
  tag[:doc] = :multiline
28
33
  tag
@@ -45,5 +50,25 @@ module JsDuck::Tag
45
50
  h[:properties] = nested[:properties]
46
51
  h[:name] = nested[:name]
47
52
  end
53
+
54
+ def process_code(code)
55
+ h = super(code)
56
+ h[:type] = code[:type]
57
+ h[:default] = code[:default]
58
+ h[:accessor] = code[:accessor]
59
+ h[:evented] = code[:evented]
60
+ h
61
+ end
62
+
63
+ # Do the merging of :type field
64
+ def merge(h, docs, code)
65
+ if h[:type] == nil
66
+ h[:type] = code[:tagname] == :method ? "Function" : "Object"
67
+ end
68
+ end
69
+
70
+ def to_html(cfg, cls)
71
+ member_link(cfg) + " : " + cfg[:html_type]
72
+ end
48
73
  end
49
74
  end
@@ -5,7 +5,6 @@ module JsDuck::Tag
5
5
  def initialize
6
6
  @pattern = "class"
7
7
  @tagname = :class
8
- @merge_context = :class
9
8
  end
10
9
 
11
10
  # @class name
@@ -20,9 +19,53 @@ module JsDuck::Tag
20
19
  h[:name] = tags[0][:name]
21
20
  end
22
21
 
23
- # Ensure the empty members array.
22
+ # Although class is not a member, it also has the auto-detected
23
+ # part from code. So this method gets called by Merger.
24
+ #
25
+ # If we did detect code as a class use all the auto-detected
26
+ # fields, otherwise use only the name field.
27
+ def process_code(code)
28
+ if code[:tagname] == :class
29
+ code
30
+ else
31
+ {:name => code[:name] }
32
+ end
33
+ end
34
+
24
35
  def merge(h, docs, code)
36
+ # Ensure the empty members array.
25
37
  h[:members] = []
38
+ # Ignore extending of the Object class
39
+ h[:extends] = nil if h[:extends] == "Object"
40
+ # Default alternateClassNames list to empty array
41
+ h[:alternateClassNames] = [] unless h[:alternateClassNames]
42
+ # Turn :aliases field into hash
43
+ h[:aliases] = build_aliases_hash(h[:aliases] || [])
44
+
45
+ # Takes the :enum always from docs, but the :doc_only can come
46
+ # from either code or docs.
47
+ if docs[:enum]
48
+ h[:enum] = docs[:enum]
49
+ h[:enum][:doc_only] = docs[:enum][:doc_only] || (code[:enum] && code[:enum][:doc_only])
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ # Given array of full alias names like "foo.bar", "foo.baz"
56
+ # build hash like {"foo" => ["bar", "baz"]}
57
+ def build_aliases_hash(aliases)
58
+ hash={}
59
+ aliases.each do |a|
60
+ if a =~ /^([^.]+)\.(.+)$/
61
+ if hash[$1]
62
+ hash[$1] << $2
63
+ else
64
+ hash[$1] = [$2]
65
+ end
66
+ end
67
+ end
68
+ hash
26
69
  end
27
70
  end
28
71
  end
@@ -1,17 +1,21 @@
1
- require "jsduck/tag/tag"
1
+ require "jsduck/tag/member_tag"
2
2
 
3
3
  module JsDuck::Tag
4
4
  # As of now there is no @css_mixin tag available in CSS files. This
5
5
  # class just exists to define that we have a member type called
6
6
  # :css_mixin.
7
- class CssMixin < Tag
7
+ class CssMixin < MemberTag
8
8
  def initialize
9
+ @tagname = :css_mixin
9
10
  @member_type = {
10
- :name => :css_mixin,
11
- :category => :method_like,
12
11
  :title => "CSS Mixins",
13
12
  :position => MEMBER_POS_CSS_MIXIN,
13
+ :icon => File.dirname(__FILE__) + "/icons/css_mixin.png"
14
14
  }
15
15
  end
16
+
17
+ def to_html(mixin, cls)
18
+ member_link(mixin) + member_params(mixin[:params])
19
+ end
16
20
  end
17
21
  end
@@ -1,22 +1,27 @@
1
- require "jsduck/tag/tag"
1
+ require "jsduck/tag/member_tag"
2
2
 
3
3
  module JsDuck::Tag
4
- class CssVar < Tag
4
+ class CssVar < MemberTag
5
5
  def initialize
6
6
  @pattern = "var"
7
7
  @tagname = :css_var
8
8
  @member_type = {
9
- :name => :css_var,
10
- :category => :property_like,
11
9
  :title => "CSS Variables",
12
10
  :toolbar_title => "CSS Vars",
13
11
  :position => MEMBER_POS_CSS_VAR,
12
+ :icon => File.dirname(__FILE__) + "/icons/css_var.png"
14
13
  }
15
14
  end
16
15
 
17
16
  # @var {Type} [name=default] ...
18
17
  def parse_doc(p, pos)
19
- p.standard_tag({:tagname => :css_var, :type => true, :name => true})
18
+ p.standard_tag({
19
+ :tagname => :css_var,
20
+ :type => true,
21
+ :name => true,
22
+ :default => true,
23
+ :optional => true
24
+ })
20
25
  end
21
26
 
22
27
  def process_doc(h, tags, pos)
@@ -25,5 +30,21 @@ module JsDuck::Tag
25
30
  h[:type] = p[:type]
26
31
  h[:default] = p[:default]
27
32
  end
33
+
34
+ def process_code(code)
35
+ h = super(code)
36
+ h[:type] = code[:type]
37
+ h[:default] = code[:default]
38
+ h
39
+ end
40
+
41
+ # Set default value for :type field
42
+ def merge(h, docs, code)
43
+ h[:type] = "Object" unless h[:type]
44
+ end
45
+
46
+ def to_html(var, cls)
47
+ member_link(var) + " : " + var[:html_type]
48
+ end
28
49
  end
29
50
  end